wolfcryp RSA Parse Key Segmentation Failed - c

Am trying to verify a message using RSA public key with help of WolfCrypt library. The message signing and verification is done using Openssl is successful with below commands.
openssl dgst -sha256 -sign private.pem -out Message.sign.rsa1024-sha-256 Message.txt
openssl dgst -sha256 -verify public.der -signture Message.sign.rsa1024-sha-256 Message.txt
Now, while trying to write a program using WolfCrypt library to verify the message(the program is not complete, Am stuck at parse public key part), the program is raising segmentation fault while parsing the public key itself. However, while trying to debug the program using GDB, the parse key section of code executes does not raise any segmentation fault and going to next step and exiting normally.
To avoid segfault, I tried malloc instead, still getting alloc(): memory corruption error.
It looks like the problem lies in wc_RsaPublicKeyDecode parameters. on GDB, while step-in to this function, the parameters looks empty. Any suggestion is welcome.
#include <stdio.h>
#include <stdlib.h>
/* Import APIs for Signing and Verification */
#include "wolfssl/wolfcrypt/rsa.h"
#include "wolfssl/wolfcrypt/hash.h"
#include "wolfssl/wolfcrypt/signature.h"
/* Import WolfSSL Types */
#include "wolfssl/wolfcrypt/types.h"
typedef struct wrap_Key
{
word32 _KeyIndex;
RsaKey _RsaKey;
}Key_t;
typedef struct wrap_Signature
{
/* Signature Algorithms */
enum wc_SignatureType _TYPE;
enum wc_HashType _DIGEST;
/* Message & Signature */
byte *_Message;
word32 _MessageLength;
byte *_Signature;
word32 _SignatureLength;
byte *_KeyBuffer;
word32 _KeyBufferLength;
/* RSA Key Structure */
Key_t _PKCS;
}Signature_t;
static int wrap_ReadFileToBuffer( byte **BufferData, word32* BufferLength, byte* URI )
{
int ret = EXIT_SUCCESS;
FILE *file = NULL;
file = fopen(URI, "r");
if( NULL == file )
{
printf( "Error! Unable to stat file.\r\n" );
return EXIT_FAILURE;
}
/* Get content length & Reset Cursor */
fseek( file, 0, SEEK_END );
*BufferLength = (word32) ftell(file);
fseek( file, 0, SEEK_SET );
/* Allocate Enough Buffer */
*BufferData = (byte*)(malloc( *BufferLength ));
if( NULL == *BufferData )
{
fclose(file);
printf("Error! Memory Allocation Failed.\r\n");
return EXIT_FAILURE;
}
/* Read File Content */
if( ( ret = fread( *BufferData, 1, *BufferLength, file ) )
!= *BufferLength )
{
fclose(file);
printf("Error! Unable to read file.\r\n");
return EXIT_FAILURE;
}
fclose(file);
return ret;
}
Signature_t *RSA1;
int main()
{
int ret = EXIT_SUCCESS;
RSA1 = malloc(sizeof(Signature_t));
/* Define Signagure & Type */
RSA1->_TYPE = WC_SIGNATURE_TYPE_RSA;
RSA1->_DIGEST = WC_HASH_TYPE_SHA256;
/* Initialize Message & Signature */
RSA1->_Message = NULL;
RSA1->_Signature = NULL;
/* Verify does the Hash given above is supproted? */
if( wc_HashGetDigestSize( RSA1->_DIGEST ) <= 0 )
{
printf("Hash type %d not supported!\n", RSA1->_DIGEST);
return EXIT_FAILURE;
}
if( wrap_ReadFileToBuffer( &(RSA1->_Message),
&(RSA1->_MessageLength), "Message.txt" ) <= 0 )
{
printf("Error! Reading Message Failed.\r\n");
return EXIT_FAILURE;
}
if( wrap_ReadFileToBuffer( &(RSA1->_Signature),
&(RSA1->_SignatureLength),
"Message.sign.rsa1024-sha-256" ) <= 0 )
{
printf("Error! Reading Signature Failed.\r\n");
return EXIT_FAILURE;
}
if( wrap_ReadFileToBuffer( &(RSA1->_KeyBuffer), &(RSA1->_KeyBufferLength),
"public.der" ) <= 0 )
{
printf("Error! Reading Key Failed.\r\n");
return EXIT_FAILURE;
}
if( ( ret = wc_InitRsaKey( &(RSA1->_PKCS._RsaKey), NULL ) ) )
{
printf("Error! Initialize Key Failed: -%d.\r\n", -ret);
return EXIT_FAILURE;
}
RSA1->_PKCS._KeyIndex = 0;
if( ( ret = wc_RsaPublicKeyDecode( RSA1->_KeyBuffer,
&RSA1->_PKCS._KeyIndex,
&RSA1->_PKCS._RsaKey,
RSA1->_KeyBufferLength ) ) )
{
printf("Error! Reading Key Failed: -%d.\r\n", -ret);
return EXIT_FAILURE;
}
free(RSA1);
printf("WolfCrypt - Sample program!\r\n");
return ret;
}
While trying to debug using GDB, found that after wc_InitRsaKey function, the entire structure *RSA1 is getting char array(byte here) is missing it's data.
(gdb) p *RSA1
$43 = {_TYPE = WC_SIGNATURE_TYPE_RSA, _DIGEST = WC_HASH_TYPE_SHA256,
_Message = 0x5555557585d0 "This is sample message to be signed!\n", _MessageLength = 37,
_Signature = 0x555555758600 "$\372\324#\340M\353\"\216\226\302V\372\265\210\242\377\362\343ɮ\032\021\206K\016/\f2\002\020!\274\234\024\212,\034\276\276,31\217\277\274sP\341c\024=u\236\233l\207\330\320>Ė\300K\211]\325\322x\307_9\251\017#\021&apos;\225Oƞ\276\311\a\177\063`\016\271G8\r;\201\036,7x\246\251Wd\246j\273\272\220\304\354\244\305\370\027\321\312\017\250n\336&apos;\375v{\251\267\270\237M", _SignatureLength = 128,
_KeyBuffer = 0x555555758690 "0\201\237\060\r\006\t*\206H\206\367\r\001\001\001\005",
_KeyBufferLength = 162, _PKCS = {_KeyIndex = 0, _RsaKey = {n = {used = 0, alloc = 0,
sign = 0, dp = 0x0}, e = {used = 0, alloc = 0, sign = 0, dp = 0x0}, d = {used = 0,
alloc = 0, sign = 0, dp = 0x0}, p = {used = 0, alloc = 0, sign = 0, dp = 0x0}, q = {
used = 0, alloc = 0, sign = 0, dp = 0x0}, dP = {used = 0, alloc = 0, sign = 0,
dp = 0x0}, dQ = {used = 0, alloc = 0, sign = 0, dp = 0x0}, u = {used = 0, alloc = 0,
sign = 0, dp = 0x0}, heap = 0x0, data = 0x0, type = 0, state = 0, dataLen = 0,
dataIsAlloc = 0 &apos;\000&apos;}}}
(gdb) n
133 RSA1->_PKCS._KeyIndex = 0;
(gdb) p *RSA1
$44 = {_TYPE = WC_SIGNATURE_TYPE_RSA, _DIGEST = WC_HASH_TYPE_SHA256,
_Message = 0x5555557585d0 "", _MessageLength = 37, _Signature = 0x555555758600 "",
_SignatureLength = 128, _KeyBuffer = 0x555555758690 "", _KeyBufferLength = 162, _PKCS = {
_KeyIndex = 0, _RsaKey = {n = {used = 0, alloc = 0, sign = 0, dp = 0x0}, e = {used = 0,
alloc = 0, sign = 0, dp = 0x0}, d = {used = 0, alloc = 0, sign = 0, dp = 0x0}, p = {
used = 0, alloc = 0, sign = 0, dp = 0x0}, q = {used = 0, alloc = 0, sign = 0,
dp = 0x0}, dP = {used = 0, alloc = 0, sign = 0, dp = 0x0}, dQ = {used = 0, alloc = 0,
sign = 0, dp = 0x0}, u = {used = 0, alloc = 0, sign = 0, dp = 0x0}, heap = 0x0,
data = 0x0, type = 0, state = 0, dataLen = 0, dataIsAlloc = 0 &apos;\000&apos;}}}

#Gopi,
The most common cause of such a segmentation fault is a misconfiguration of application and library. The first thing to check is the headers included.
/* Import APIs for Signing and Verification */
#include "wolfssl/wolfcrypt/rsa.h"
#include "wolfssl/wolfcrypt/hash.h"
#include "wolfssl/wolfcrypt/signature.h"
/* Import WolfSSL Types */
#include "wolfssl/wolfcrypt/types.h"
Notice that neither "wolfssl/options.h" or "wolfssl/wolfcrypt/settings.h" was included. If you built the wolfSSL library with ./configure && make please include "wolfssl/options.h" before all other wolfSSL headers. If you are only using "wolfssl/wolfcrypt/settings.h" to control the build and options.h is not found then at least include "wolfssl/wolfcrypt/settings.h" before all other wolfSSL headers:
/* Import APIs for Signing and Verification */
#include <wolfssl/options.h> // If not found or not available then include <wolfssl/wolfcrypt/settings.h>
#include "wolfssl/wolfcrypt/rsa.h"
#include "wolfssl/wolfcrypt/hash.h"
#include "wolfssl/wolfcrypt/signature.h"
/* Import WolfSSL Types */
#include "wolfssl/wolfcrypt/types.h"
Cheers,
K

Related

How to extend a volume programmatically

My requirement is to extend drive volume through program. When I used IOCTL_DISK_GROW_PARTITION in DeviceIO to extend it, the disk management shows the new modified size while the size of the drive in This PC (My Computer) remains unchanged.
BOOL DeviceIoControl(
(HANDLE) hDevice, // handle to device
IOCTL_DISK_GROW_PARTITION, // dwIoControlCode
(LPVOID) lpInBuffer, // input buffer
(DWORD) nInBufferSize, // size of the input buffer
NULL, // lpOutBuffer
0, // nOutBufferSize
(LPDWORD) lpBytesReturned, // number of bytes returned
(LPOVERLAPPED) lpOverlapped // OVERLAPPED structure
);
Through some analysis I found that while using this API the MBR of the disk is modified but the cluster bitmap of drive is not changed. I want to know the correct way of using this DeviceIO to expand a volume or some other API to do the same process.
need understand different between disk driver, which maintain info about disk layout and partitions (it size, offset from disk begin, style (gpt or mbr) ) and file system, which mount this partition.
IOCTL_DISK_GROW_PARTITION - this ioctl is handled by disk driver and extend partition, but this can not have effect for file system, which not handle this ioctl and have no knowledge at all that partition was extended. so you need additional ioctl use FSCTL_EXTEND_VOLUME - this ioctl already send and handle to file-system.
so if we have to do next steps
send IOCTL_DISK_GROW_PARTITION with
DISK_GROW_PARTITION as input buffer
send IOCTL_DISK_UPDATE_DRIVE_SIZE with DISK_GEOMETRY
as output buffer
send IOCTL_DISK_GET_PARTITION_INFO_EX with
PARTITION_INFORMATION_EX as output for get actual size of
partition now.
calculate new size of the volume, in sectors
LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart / dg.BytesPerSector;
(dg we got at step 2 and PartitionEntry at step 3)
finally use FSCTL_EXTEND_VOLUME
full code can be like next
int __cdecl SortPartitions(PPARTITION_INFORMATION_EX PartitionEntry1, PPARTITION_INFORMATION_EX PartitionEntry2)
{
if (!PartitionEntry1->PartitionNumber) return PartitionEntry2->PartitionNumber ? -1 : 0;
if (!PartitionEntry2->PartitionNumber) return +1;
if (PartitionEntry1->StartingOffset.QuadPart < PartitionEntry2->StartingOffset.QuadPart) return -1;
if (PartitionEntry1->StartingOffset.QuadPart > PartitionEntry2->StartingOffset.QuadPart) return +1;
return 0;
}
DWORD ExtendTest(HANDLE hDisk)
{
STORAGE_DEVICE_NUMBER sdn;
ULONG dwBytesRet;
if (!DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesRet, NULL))
{
return GetLastError();
}
if (sdn.DeviceType != FILE_DEVICE_DISK || sdn.PartitionNumber != 0)
{
return ERROR_GEN_FAILURE;
}
GET_LENGTH_INFORMATION gli;
if (!DeviceIoControl(hDisk, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), &dwBytesRet, NULL))
{
return GetLastError();
}
DbgPrint("Disk Length %I64x (%I64u)\n", gli.Length.QuadPart, gli.Length.QuadPart);
PVOID stack = alloca(guz);
union {
PVOID buf;
PDRIVE_LAYOUT_INFORMATION_EX pdli;
};
ULONG cb = 0, rcb, PartitionCount = 4;
for (;;)
{
if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buf, cb, &dwBytesRet, NULL))
{
if (PartitionCount = pdli->PartitionCount)
{
PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;
qsort(PartitionEntry, PartitionCount, sizeof(PARTITION_INFORMATION_EX),
(int (__cdecl *)(const void *, const void *))SortPartitions );
do
{
if (!PartitionEntry->PartitionNumber)
{
continue;
}
LARGE_INTEGER EndOffset;
LARGE_INTEGER MaximumOffset = PartitionCount != 1 ? (PartitionEntry + 1)->StartingOffset : gli.Length;
EndOffset.QuadPart = PartitionEntry->StartingOffset.QuadPart + PartitionEntry->PartitionLength.QuadPart;
if (EndOffset.QuadPart > MaximumOffset.QuadPart)
{
//??
__debugbreak();
}
else if (EndOffset.QuadPart < MaximumOffset.QuadPart)
{
DISK_GROW_PARTITION dgp;
dgp.PartitionNumber = PartitionEntry->PartitionNumber;
dgp.BytesToGrow.QuadPart = MaximumOffset.QuadPart - EndOffset.QuadPart;
WCHAR sz[128];
swprintf(sz, L"\\\\?\\GLOBALROOT\\Device\\Harddisk%d\\Partition%u", sdn.DeviceNumber, dgp.PartitionNumber);
HANDLE hPartition = CreateFile(sz, FILE_READ_ACCESS|FILE_WRITE_ACCESS, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hPartition != INVALID_HANDLE_VALUE)
{
// +++ begin extend
BOOL fOk = FALSE;
DISK_GEOMETRY dg;
if (DeviceIoControl(hPartition, IOCTL_DISK_GROW_PARTITION, &dgp, sizeof(dgp), 0, 0, &dwBytesRet, 0) &&
DeviceIoControl(hPartition, IOCTL_DISK_UPDATE_DRIVE_SIZE, 0, 0, &dg, sizeof(dg), &dwBytesRet, 0) &&
DeviceIoControl(hPartition, IOCTL_DISK_GET_PARTITION_INFO_EX, 0, 0, PartitionEntry, sizeof(*PartitionEntry), &dwBytesRet, 0)
)
{
LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart / dg.BytesPerSector;
fOk = DeviceIoControl(hPartition, FSCTL_EXTEND_VOLUME, &SectorsPerPartition,
sizeof(SectorsPerPartition), 0, 0, &dwBytesRet, 0);
}
if (!fOk)
{
GetLastError();
}
//--- end extend
CloseHandle(hPartition);
}
}
// else EndOffset.QuadPart == MaximumOffset.QuadPart - partition can not be extended
} while (PartitionEntry++, --PartitionCount);
}
return NOERROR;
}
switch (ULONG err = GetLastError())
{
case ERROR_MORE_DATA:
PartitionCount = pdli->PartitionCount;
continue;
case ERROR_BAD_LENGTH:
case ERROR_INSUFFICIENT_BUFFER:
PartitionCount <<= 1;
continue;
default:
return err;
}
}
}
DWORD ExtendTest()
{
HANDLE hDisk = CreateFileW(L"\\\\?\\PhysicalDrive0", FILE_GENERIC_READ|FILE_GENERIC_WRITE,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hDisk != INVALID_HANDLE_VALUE)
{
DWORD err = ExtendTest(hDisk);
CloseHandle(hDisk);
return err;
}
return GetLastError();
}

SCSI Read(10) on a Physical Drive on Windows

I tried issuing a SCSI Read(10) command to a physical drive on a Windows 7 machine. Below is the code snippet that I am using. It is failing with error code 87.
void scsi_read()
{
const UCHAR cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 512, 0 };
UCHAR buf[512];
BYTE senseBuf[196];
const int SENSE_LENGTH = 196;
LPCSTR fname = "\\\\.\\E:";
HANDLE fh;
DWORD ioctl_bytes;
DWORD err = 0;
SCSI_PASS_THROUGH s = {0};
memcpy(s.Cdb, cdb, sizeof(cdb));
s.CdbLength = 10;
s.DataIn = SCSI_IOCTL_DATA_IN;
s.TimeOutValue = 30;
s.Length = sizeof(SCSI_PASS_THROUGH);
s.ScsiStatus = 0x00;
s.SenseInfoOffset = senseBuf;
s.SenseInfoLength = SENSE_LENGTH;
s.DataBufferOffset = buf;
s.DataTransferLength = 512;
fh = CreateFile("\\\\.\\E:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if(fh == INVALID_HANDLE_VALUE) {
printf("Could not open %s file, error %d\n", fname, GetLastError());
return (FALSE);
}
int ret = DeviceIoControl(fh,IOCTL_SCSI_PASS_THROUGH, &s,sizeof(s), //scsiPassThrough.sizeof,
&s,
sizeof(s),
&ioctl_bytes,
NULL);
printf("ret %d",(int)ret);
if (ret==1) {
printf("OK");
}
else {
err = GetLastError();
printf("Last error code %u\n", err);
printf("Return size %d\n", ioctl_bytes);
printf("Sense data\n");
int i=0;
for (i = 0; i < 20; i++) {
printf("\t%x", senseBuf[i]);
}
printf("\n");
}
CloseHandle(fh);
}
Error: Hex dumps are printed in the output
you got error code 87 - ERROR_INVALID_PARAMETER because code totally wrong.
for example:
const UCHAR cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 512, 0 };
but 512 is > 255 (MAXUCHAR) are you not got compiler warning here ?
warning C4305: 'initializing': truncation from 'int' to 'const UCHAR'
look at this line !
s.DataBufferOffset = buf;
from SCSI_PASS_THROUGH structure:
DataBufferOffset
Contains an offset from the beginning of this structure to the data
buffer. The offset must respect the data alignment requirements of the
device.
so offset to buffer, not pointer to buffer
for use this correct you code need be like this:
struct MY_DATA : SCSI_PASS_THROUGH
{
UCHAR buf[512];
} s;
s.DataBufferOffset = FIELD_OFFSET(MY_DATA, buf);
but better use SCSI_PASS_THROUGH_DIRECT with IOCTL_SCSI_PASS_THROUGH_DIRECT
you hardcode sector size (512), when need get it at runtime. and how you initialize CDB ?!? at all unclear what you try todo.
working code example (sorry but on c++ instead c)
#define _NTSCSI_USER_MODE_
#include <scsi.h>
#include <ntddscsi.h>
BOOL scsi_read(HANDLE fh, PVOID buf, DWORD cb, ULONGLONG LogicalBlock, ULONG TransferBlocks)
{
SCSI_PASS_THROUGH_DIRECT s = {
sizeof(SCSI_PASS_THROUGH_DIRECT), 0, 0, 0, 0, 0, 0, SCSI_IOCTL_DATA_IN, cb, 30, buf
};
union {
PUCHAR Cdb;
CDB::_CDB10* Cdb10;
CDB::_CDB16* Cdb16;
};
Cdb = s.Cdb;
if (MAXULONG < LogicalBlock || MAXUSHORT < TransferBlocks)
{
s.CdbLength = sizeof(CDB::_CDB16);
Cdb16->OperationCode = SCSIOP_READ16;
*(ULONGLONG*)Cdb16->LogicalBlock = _byteswap_uint64(LogicalBlock);
*(ULONG*)Cdb16->TransferLength = _byteswap_ulong(TransferBlocks);
}
else
{
s.CdbLength = sizeof(CDB::_CDB10);
Cdb10->OperationCode = SCSIOP_READ;
*(ULONG*)&Cdb10->LogicalBlockByte0 = _byteswap_ulong((ULONG)LogicalBlock);
*(USHORT*)&Cdb10->TransferBlocksMsb = _byteswap_ushort((USHORT)TransferBlocks);
}
DWORD ioctl_bytes;
return DeviceIoControl(fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &s, sizeof(s), &s, sizeof(s), &ioctl_bytes, NULL);
}
BOOL test_scsi_read(PCWSTR fname)
{
BOOL fOk = FALSE;
HANDLE fh = CreateFileW(fname, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (fh != INVALID_HANDLE_VALUE)
{
DWORD ioctl_bytes;
DISK_GEOMETRY_EX dg;
if (DeviceIoControl(fh, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &dg, sizeof(dg), &ioctl_bytes, 0))
{
// 16 sectors for example
ULONG cb = 16 * dg.Geometry.BytesPerSector;
if (PVOID buf = new CHAR[cb])
{
// read first 16 sectors
fOk = scsi_read(fh, buf, cb, 0, 16);
if (ULONGLONG LogicalBlock = dg.DiskSize.QuadPart / dg.Geometry.BytesPerSector)
{
// read last sector
fOk = scsi_read(fh, buf, dg.Geometry.BytesPerSector, LogicalBlock - 1, 1);
}
delete buf;
}
}
CloseHandle(fh);
}
return fOk;
}
test_scsi_read(L"\\\\?\\e:");

Creating file with FAT file-system

I have this problem : I'm using FAT FS and LPC4088 and after I divided physical drive with f_fdisk, and mounting two partitions apparently without problems ( I get FR_OK as result value for every used fs function), then I create a file, I write on it and then close it, always with a FR_OK result value. Then I check the file and I get a FR_NO_FILE error
The code look like this
static FILINFO fno;
static FIL fdst;
static DWORD plist[] = {50, 50, 0, 0};
FRESULT rc;
char error;
static BYTE work[512];
error = 0;
rc = f_fdisk(0, plist, work); /* Divide physical drive 0 */
/* rc=FR_OK */
rc = f_mount(&FS1, "0:", 1); /* Register work area to the logical drive 0 */
if (rc!=FR_OK)
{
rc = f_mkfs("0:", 0, 0);
}
rc = f_mount(&FS2, "1:", 1); /* Register a work area to the logical drive 1 */
if (rc!=FR_OK)
{
rc = f_mkfs("1:", 0, 0);
}
rc = f_open(&fdst, "0:myfile.bin", FA_WRITE | FA_CREATE_ALWAYS);
if (rc!=FR_OK) error =1; /* rc=FR_OK */
rc = f_write(&fdst,"abcde",5,&nwritten);
if (rc!=FR_OK) error =2; /* rc=FR_OK */
rc = f_close(&fdst);
if (rc!=FR_OK) error =2; /* rc=FR_OK */
rc = f_stat("0:myfile.bin", &fno);
if (rc!=FR_OK) error =4; /*rc = FR_NO_FILE*/
Any suggestion would be very appreciated.

How to use ldap_sasl_bind in WinLDAP?

I currently use ldap_bind_s to bind to the server in my C application with SEC_WINNT_AUTH_IDENTITY struct, but the function is marked as deprecated. For this reason I would like to change it to the ldap_sasl_bind_s function.
int main(void) {
LDAP *ld;
int rc = 0;
char *binddn = "cn=admin,dc=local";
const int version = LDAP_VERSION3;
SEC_WINNT_AUTH_IDENTITY wincreds;
struct berval saslcred;
wincreds.User = "admin";
wincreds.UserLength = 5;
wincreds.Password = "secret";
wincreds.PasswordLength = 6;
wincreds.Domain = NULL;
wincreds.DomainLength = 0;
wincreds.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
ld = ldap_initA("localhost", LDAP_PORT);
ldap_set_optionA(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
rc = ldap_bind_sA(ld, binddn, (PCHAR)&wincreds, LDAP_AUTH_DIGEST);
printf("0x%x\n", rc); // It's OK (0x0)
ldap_unbind(ld);
saslcred.bv_val = "secret";
saslcred.bv_len = 6;
rc = ldap_sasl_bind_sA(ld, binddn, "DIGEST-MD5", &saslcred, NULL, NULL, NULL);
printf("0x%x\n", rc); // Returns with 0x59
ldap_unbind(ld)
return 0;
}
The ldap_sasl_bind_s returns with LDAP_PARAM_ERROR code. Clearly, the function parameters are wrong above, but I can't find a working sample code with winldap and SASL binding.
I would be grateful for some guide, how to make this code working.
The last parameter of ldap_sasl_bind_sA cannot be NULL. It has to point to a place the function can put the server's response (struct berval*).
...
struct berval* serverResponse = NULL;
rc = ldap_sasl_bind_sA(ld, binddn, "DIGEST-MD5", &saslcred, NULL, NULL, &serverResponse);
...
So finally, after some research and debugging in the past two weeks, I've managed to write a working example code that uses DIGEST-MD5 authentication with WinLDAP's ldap_sasl_bind_s function. The corresponding RFC, this answer and the official SSPI documentation gave me a lot of helps.
Some gotchas that I ran into:
Regardless what documentation says about the ldap_connect function: If you would like to use the ldap_sasl_bind_s function it is not just a "good programming practice" to call it first, it is necessary. Without it the ldap_sasl_bind_s returns with LDAP_SERVER_DOWN (0x51) error code.
The valid pszTargetName (digest-uri) parameter is crucial for the InitializeSecurityContext function to avoid invalid token error.
I hope it will help others to spend less time about figuring out how to use SASL binding mechanisms with WinLDAP.
#include <stdio.h>
#include <windows.h>
#include <winldap.h>
#define SECURITY_WIN32 1
#include <security.h>
#include <sspi.h>
int _tmain(int argc, _TCHAR* argv[]) {
LDAP *ld;
int rc = 0;
const int version = LDAP_VERSION3;
SEC_WINNT_AUTH_IDENTITY wincreds;
struct berval *servresp = NULL;
SECURITY_STATUS res;
CredHandle credhandle;
CtxtHandle newhandle;
SecBufferDesc OutBuffDesc;
SecBuffer OutSecBuff;
SecBufferDesc InBuffDesc;
SecBuffer InSecBuff;
unsigned long contextattr;
ZeroMemory(&wincreds, sizeof(wincreds));
// Set credential information
wincreds.User = (unsigned short *)L"root";
wincreds.UserLength = 4;
wincreds.Password = (unsigned short *)L"p#ssword";
wincreds.PasswordLength = 8;
wincreds.Domain = NULL;
wincreds.DomainLength = 0;
wincreds.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
res = AcquireCredentialsHandle(NULL, L"WDigest", SECPKG_CRED_OUTBOUND,
NULL, &wincreds, NULL, NULL, &credhandle, NULL);
// Buffer for the output token.
OutBuffDesc.ulVersion = 0;
OutBuffDesc.cBuffers = 1;
OutBuffDesc.pBuffers = &OutSecBuff;
OutSecBuff.BufferType = SECBUFFER_TOKEN;
OutSecBuff.pvBuffer = NULL;
ld = ldap_init(L"localhost", LDAP_PORT);
rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void*)&version);
rc = ldap_connect(ld, NULL); // Need to connect before SASL bind!
do {
if (servresp != NULL) {
InBuffDesc.ulVersion = 0;
InBuffDesc.cBuffers = 1;
InBuffDesc.pBuffers = &InSecBuff;
/* The digest-challenge will be passed as an input buffer to
InitializeSecurityContext function */
InSecBuff.cbBuffer = servresp->bv_len;
InSecBuff.BufferType = SECBUFFER_TOKEN;
InSecBuff.pvBuffer = servresp->bv_val;
/* The OutBuffDesc will contain the digest-response. */
res = InitializeSecurityContext(&credhandle, &newhandle, L"ldap/localhost", ISC_REQ_MUTUAL_AUTH | ISC_REQ_ALLOCATE_MEMORY,
0, 0, &InBuffDesc, 0, &newhandle, &OutBuffDesc, &contextattr, NULL);
}
else {
res = InitializeSecurityContext(&credhandle, NULL, L"ldap/localhost", ISC_REQ_MUTUAL_AUTH, 0, 0, NULL, 0, &newhandle, &OutBuffDesc, &contextattr, NULL);
}
switch (res) {
case SEC_I_COMPLETE_NEEDED:
case SEC_I_COMPLETE_AND_CONTINUE:
case SEC_E_OK:
case SEC_I_CONTINUE_NEEDED:
break;
case SEC_E_INVALID_HANDLE:
return -2;
case SEC_E_INVALID_TOKEN:
return -1;
default:
break;
}
struct berval cred;
cred.bv_len = OutSecBuff.cbBuffer;
/* The digest-response will be passed to the server
as credential after the second (loop)run. */
cred.bv_val = (char *)OutSecBuff.pvBuffer;
// The servresp will contain the digest-challange after the first call.
rc = ldap_sasl_bind_s(ld, L"", L"DIGEST-MD5", &cred, NULL, NULL, &servresp);
ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &res)
} while (res == LDAP_SASL_BIND_IN_PROGRESS);
if (rc != LDAP_SUCCESS) {
printf("Bind failed with 0x%x\n", rc);
} else {
printf("Bind succeeded\n");
}
return 0;
}

pcre match all groups in C

I want to match a group recursively using PCRE C library.
e.g.
pattern = "(\d,)"
subject = "5,6,3,2,"
OVECCOUNT = 30
pcrePtr = pcre_compile(pattern, 0, &error, &erroffset, NULL);
rc = pcre_exec(pcrePtr, NULL, subject, (int)strlen(subject),
0, 0, ovector, OVECCOUNT);
rc is -1..
How to match all groups so that matches are "5,", "6,", "3,", "2,"
For analogy, PHP's preg_match_all parses entire string until the end of subject...
Any way I used strtok since "," was repeating after each group..
Solution using pcre is welcomed....
Try this :
pcre *myregexp;
const char *error;
int erroroffset;
int offsetcount;
int offsets[(0+1)*3]; // (max_capturing_groups+1)*3
myregexp = pcre_compile("\\d,", 0, &error, &erroroffset, NULL);
if (myregexp != NULL) {
offsetcount = pcre_exec(myregexp, NULL, subject, strlen(subject), 0, 0, offsets, (0+1)*3);
while (offsetcount > 0) {
// match offset = offsets[0];
// match length = offsets[1] - offsets[0];
if (pcre_get_substring(subject, &offsets, offsetcount, 0, &result) >= 0) {
// Do something with match we just stored into result
}
offsetcount = pcre_exec(myregexp, NULL, subject, strlen(subject), 0, offsets[1], offsets, (0+1)*3);
}
} else {
// Syntax error in the regular expression at erroroffset
}
I believe the comments are self explanatory?

Resources