How do I configure WinHTTP Tracing programmatically? - c

I have a C application (not C++ or C#) that tests connectivity to our API from a client's perspective using WinHTTP. Here's code that downloads a file.
DWORD Measure(FILE* fout, LPCTSTR lpszUrl) {
int i;
DWORD dwResult = 0;
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
DWORD dwRequestSize = 0;
LPSTR pszOutBuffer;
BOOL bResults = FALSE;
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
WINHTTP_STATUS_CALLBACK status = NULL;
if (0 == dwResult) {
hSession = WinHttpOpen(_T("Test/1.0"), WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession == NULL) {
dwResult = GetLastError();
}
}
if (0 == dwResult) {
status = WinHttpSetStatusCallback(hSession, (WINHTTP_STATUS_CALLBACK)HttpCallback, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL);
if (WINHTTP_INVALID_STATUS_CALLBACK == status) {
dwResult = GetLastError();
}
}
if (0 == dwResult) {
hConnect = WinHttpConnect(hSession, lpszUrl, INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL) {
dwResult = GetLastError();
}
}
if (0 == dwResult) {
hRequest = WinHttpOpenRequest(hConnect, L"GET", NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE | WINHTTP_FLAG_REFRESH);
if (hRequest == NULL) {
dwResult = GetLastError();
}
}
if (0 == dwResult) {
bResults = WinHttpSendRequest(hRequest,WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
}
if (0 == dwResult) {
if(!QueryPerformanceCounter(&liDownloadStart)){
dwResult = GetLastError();
}
}
if (bResults) {
bResults = WinHttpReceiveResponse(hRequest, NULL);
if (!bResults) {
dwResult = GetLastError();
}
}
if (dwResult == 0 && bResults) {
do {
dwSize = 0;
if( !WinHttpQueryDataAvailable( hRequest, &dwSize ) ){
dwResult = GetLastError();
}
if (0 == dwResult) {
dwRequestSize += dwSize;
}
pszOutBuffer = (LPSTR)malloc(dwSize+1);
if (!pszOutBuffer) {
dwResult = ERROR_OUTOFMEMORY;
}
if (dwResult == 0) {
ZeroMemory(pszOutBuffer, dwSize + 1);
if( !WinHttpReadData( hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded ) ){
dwResult = GetLastError();
}
free(pszOutBuffer);
}
} while (dwSize > 0 && dwResult == 0);
}
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
return dwResult;
}
I can enable tracing using the following module:
BOOL enable = TRUE;
WinHttpSetOption(NULL, WINHTTP_OPTION_ENABLETRACING, &enable, sizeof(enable));
Following the instructions in the article Capturing WinHTTP Logs, I could ask the user to enable tracing, including the path where files should be stored.
netsh winhttp set tracing trace-file-prefix="C:\Temp\dpws" level=verbose format=ansi state=enabled max-trace-file-size=1073741824
However, most folks running my application are technically challenged. They may forget to disable it when they are done.
How do I programmatically enable WinHTTP tracing for my process?

Related

Obtaining handle to key with NtCreateKey/NtOpenKey

PURPOSE
I'm trying to make a function which will create a given sub key in the HKCU registry hive, or open the sub key if it already exists, then return TRUE.
NOTES
Let RegSidPath represent a fully qualified HKCU registry path with an user SID appended to it such as \\Registry\\User\\S-1-5-20-xxxxxx-xxxxxx-xxxxxxxx-1050
Let KeyToCreate represent a specific registry path such as \\Software\\MyCompany\\MySoftware\\MySubKey
CODE
I have the following function:
BOOL CreateHKCUKey(PWCHAR RegSidPath, PWCHAR KeyToCreate) {
UNICODE_STRING uString;
RtlInitUnicodeString(&uString, RegSidPath);
OBJECT_ATTRIBUTES ObjAttributes;
InitializeObjectAttributes(&ObjAttributes, &uString, OBJ_CASE_INSENSITIVE, 0, 0);
HANDLE BaseKeyHandle = NULL;
NTSTATUS Status = NtOpenKey(&BaseKeyHandle, KEY_CREATE_SUB_KEY, &ObjAttributes);
if (NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) {
UNICODE_STRING KeyString = { 0 };
do {
PWCHAR NextSubKey = StrStrW((KeyString.Length == 0 ? KeyToCreate : KeyString.Buffer) + 1, L"\\");
DWORD CurrentKeyLength = lstrlenW(KeyToCreate) - lstrlenW(NextSubKey);
PWCHAR CurrentSubKey = PWCHAR(GlobalAlloc(GPTR, CurrentKeyLength + sizeof(WCHAR)));
if (CurrentSubKey != ERROR) {
memcpy(CurrentSubKey, KeyToCreate, CurrentKeyLength * sizeof(WCHAR));
CurrentSubKey[CurrentKeyLength] = UNICODE_NULL;
RtlInitUnicodeString(&KeyString, CurrentSubKey);
OBJECT_ATTRIBUTES KeyAttributes;
InitializeObjectAttributes(&KeyAttributes, &KeyString, OBJ_CASE_INSENSITIVE, &BaseKeyHandle, 0);
HANDLE CurrentHiveEntry = NULL;
Status = NtOpenKey(&CurrentHiveEntry, KEY_CREATE_SUB_KEY, &KeyAttributes);
if (RtlNtStatusToDosError(Status) == ERROR_BAD_PATHNAME) {
InitializeObjectAttributes(&KeyAttributes, &KeyString, OBJ_CASE_INSENSITIVE, &CurrentHiveEntry, 0);
DWORD DefaultDisposition;
Status = NtCreateKey(&CurrentHiveEntry, KEY_CREATE_SUB_KEY, &KeyAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &DefaultDisposition);
if (NT_SUCCESS(Status)) {
if (StrCmpNW(KeyString.Buffer + uString.Length, KeyString.Buffer, lstrlenW(KeyToCreate) == 0))
return TRUE;
else continue;
} else break;
} else break;
BaseKeyHandle = CurrentHiveEntry;
}
} while (TRUE);
}
NtClose(BaseKeyHandle);
return FALSE;
}
PROBLEM
Whenever the code gets to this part of the function
Status = NtOpenKey(&CurrentHiveEntry, KEY_CREATE_SUB_KEY, &KeyAttributes);
if (RtlNtStatusToDosError(Status) == ERROR_BAD_PATHNAME) {
The return value is always ERROR_BAD_PATHNAME (161) even if the current sub key already exists.
QUESTION
What is the reason, and what am I doing wrong? Is there anything that I've done which is not correct, and how can I fix it?
NTSTATUS CreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, PWCHAR RegSidPath, PWCHAR KeyToCreate, PULONG Disposition)
{
UNICODE_STRING ObjectName;
RtlInitUnicodeString(&ObjectName, RegSidPath);
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName ,OBJ_CASE_INSENSITIVE };
NTSTATUS status = ZwOpenKey(&oa.RootDirectory, KEY_CREATE_SUB_KEY, &oa);
if (0 <= status)
{
ObjectName.Buffer = KeyToCreate;
do
{
ACCESS_MASK Access;
if (KeyToCreate = wcschr(++ObjectName.Buffer, '\\'))
{
ObjectName.Length = (USHORT)RtlPointerToOffset(ObjectName.Buffer, KeyToCreate);
Access = KEY_CREATE_SUB_KEY;
}
else
{
ObjectName.Length = (USHORT)wcslen(ObjectName.Buffer) * sizeof(WCHAR);
Access = DesiredAccess;
}
ObjectName.MaximumLength = ObjectName.Length;
status = ZwCreateKey(KeyHandle, Access, &oa, 0, 0, 0, Disposition);
NtClose(oa.RootDirectory);
oa.RootDirectory = *KeyHandle;
} while (0 <= status && (ObjectName.Buffer = KeyToCreate));
}
return status;
}
and use as
HANDLE hKey;
NTSTATUS status = CreateKey(&hKey, KEY_ALL_ACCESS,
L"\\REGISTRY\\USER\\S-***",
L"\\Software\\MyCompany\\MySoftware\\MySubKey", 0);
Unless you are writing a driver, use RegCreateKeyEx() instead. It handles all the logic of creating intermediate keys for you if they don't already exist. 1 function call, no looping needed.
HKEY hKey;
DWORD dwDisposition;
LONG lRet = RegCreateKeyExW(HKEY_USERS, L"S-1-5-20-xxxxxx-xxxxxx-xxxxxxxx-1050\\Software\\MyCompany\\MySoftware\\MySubKey", 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hKey, &dwDisposition);
if (lRet == 0)
{
...
RegCloseKey(hKey);
}
However, to access the HKEY_CURRENT_USER hive of a specific user, the preferred solution is to use RegOpenCurrentUser() or LoadUserProfile() instead of accessing HKEY_USERS directly:
// impersonate the desired user first, then...
HKEY hRootKey;
LONG lRet = RegOpenCurrentUser(samDesired, &hRootKey);
if (lRet == 0)
{
HKEY hKey;
DWORD dwDisposition;
lRet = RegCreateKeyExW(hRootKey, L"Software\\MyCompany\\MySoftware\\MySubKey", 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hKey, &dwDisposition);
if (lRet == 0)
{
...
RegCloseKey(hKey);
}
RegCloseKey(hRootKey);
}
// stop impersonating...
// obtain token to desired user first, then...
PROFILEINFO profile = {0};
profile.dwSize = sizeof(profile);
profile.dwFlags = PI_NOUI;
if (LoadUserProfile(hToken, &profile))
{
HKEY hKey;
DWORD dwDisposition;
LONG lRet = RegCreateKeyExW((HKEY)profile.hProfile, L"Software\\MyCompany\\MySoftware\\MySubKey", 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hKey, &dwDisposition);
if (lRet == 0)
{
...
RegCloseKey(hKey);
}
UnloadUserProfile(hToken, profile.hProfile);
}
// release token ...

X509 Certificate verification with Windows Crypto API

I need to write a C program for Windows that receives a certificate from network (in PEM format) and validates its signature with a certificate chain file (which is already presented in the application's folder).
Writing such an application is pretty easy and strait forward with openssl library but seems a little complicated with the Windows Crypto API.
Here is what I've tried so far:
First I thought I can create a HCERTSTORE using the certificate-chain file:
HCERTSTORE hFileStoreHandle = CertOpenStore(
CERT_STORE_PROV_FILENAME,
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL,
(CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG),
L"certificate-chain.pem.cert");
Then I figured I can iterate through the store and get PCCERT_CONTEXT struct of certificates:
PCCERT_CONTEXT CAfileContext = NULL;
while(CAfileContext = CertEnumCertificatesInStore(
hCertStore,
CAfileContext)) {
//start verification here
}
I don't know if I am on the right track or not but I'm facing two major problems here.
First is I don't know how to get the received certificate from buffer and convert it to a proper struct in order to validate its signature with certificate-chain file.
Second is I don't know how to verify a certificate signature using the CA chain file.
I'll appreciate all the suggestions and helps.
Here is the sample code for you, hopefully it can help you.
HRESULT hr = E_FAIL;
DWORD dwError = 0;
PCCERT_CONTEXT pCert = NULL;
HCERTSTORE hCertStore = CertOpenStore(
CERT_STORE_PROV_FILENAME,
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
NULL,
(CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG),
L"certificate-chain.pem.cert");
do
{
if ((pCert = CertEnumCertificatesInStore(hCertStore, pCert)) == NULL)
break;
PCCERT_CONTEXT pcIssuer = NULL;
PCCERT_CONTEXT pcSubject = CertDuplicateCertificateContext(pCert);
for (; NULL != pcSubject;)
{
DWORD dwFlags = 0;
BOOL bret = TRUE;
hr = S_OK;
pcIssuer = CertGetIssuerCertificateFromStore(
hCertStore, pcSubject, NULL, &dwFlags);
if (pcIssuer == NULL)
{
dwError = GetLastError();
if (CRYPT_E_SELF_SIGNED != dwError)
{
hr = E_FAIL;
break;
}
else
{
if ((bret = CertCompareCertificateName(
X509_ASN_ENCODING,
&pcSubject->pCertInfo->Subject,
&pcSubject->pCertInfo->Issuer)) == FALSE)
{
hr = E_FAIL;
break;
}
}
}
HCRYPTPROV hprov = NULL;
bret = CryptAcquireContext(
&hprov, nullptr, nullptr, PROV_RSA_FULL,
CRYPT_SILENT | CRYPT_VERIFYCONTEXT | CRYPT_NEWKEYSET);
if (FALSE == bret)
{
dwError = GetLastError();
if (NTE_EXISTS == dwError)
bret = CryptAcquireContext(
&hprov, nullptr, nullptr, PROV_RSA_FULL,
CRYPT_SILENT | CRYPT_VERIFYCONTEXT);
if (FALSE == bret)
{
hr = E_FAIL;
break;
}
}
if ((bret = CryptVerifyCertificateSignatureEx(
hprov, X509_ASN_ENCODING,
CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
(void*)pcSubject,
CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
(void*)(pcIssuer == nullptr ? pcSubject : pcIssuer),
0, nullptr)) == FALSE)
{
hr = E_FAIL;
break;
}
if (nullptr == pcIssuer)
{
CERT_PUBLIC_KEY_INFO msCert;
msCert.Algorithm =
pcSubject->pCertInfo->SubjectPublicKeyInfo.Algorithm;
msCert.PublicKey.cbData =
sizeof(PETRUSTED_ROOTCERT_PUBKEY);
msCert.PublicKey.pbData =
const_cast<LPBYTE>(PETRUSTED_ROOTCERT_PUBKEY);
msCert.PublicKey.cUnusedBits =
pcSubject->pCertInfo->SubjectPublicKeyInfo.PublicKey.cUnusedBits;
if (FALSE == CertComparePublicKeyInfo(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
&pcSubject->pCertInfo->SubjectPublicKeyInfo, &msCert))
{
hr = E_FAIL;
break;
}
}
bret = CryptReleaseContext(hprov, 0);
hprov = NULL;
CertFreeCertificateContext(pcSubject);
pcSubject = pcIssuer;
pcIssuer = NULL;
}
if (pcIssuer != NULL)
CertFreeCertificateContext(pcIssuer);
if (pcSubject != NULL)
CertFreeCertificateContext(pcSubject);
if (FAILED(hr))
{
CertFreeCertificateContext(pCert);
break;
}
} while (pCert != NULL);
CertCloseStore(hCertStore, 0);
if (FAILED(hr))
wprintf(L"Failed to verify X509 certification.\n");
else
wprintf(L"Successfully verify X509 certification.\n");

How to set l2tp preshared key?

I need to create RASENTRY for L2TP with pre-shared key set. So far, I can see that entry has somewhat correct flags, but no key is set, unfortunately.
Here is code:
int common_ras_manager_create_entry(const char* server_address, const char* username, const char* password, MY_VPN_CONNECTION_TYPE connection_type, const char* preshared_key)
{
DWORD EntryInfoSize = 0;
DWORD DeviceInfoSize = 0;
DWORD Ret;
LPRASENTRY lpRasEntry;
LPBYTE lpDeviceInfo;
// Get buffer sizing information for a default phonebook entry
if ((Ret = RasGetEntryProperties(NULL, "", NULL, &EntryInfoSize, lpDeviceInfo, &DeviceInfoSize)) != 0)
{
if (Ret != ERROR_BUFFER_TOO_SMALL)
{
printf("RasGetEntryProperties sizing failed with error %d\n", Ret);
return Ret;
}
}
lpRasEntry = (LPRASENTRY) GlobalAlloc(GPTR, EntryInfoSize);
if (DeviceInfoSize == 0)
lpDeviceInfo = NULL;
else
lpDeviceInfo = (LPBYTE) GlobalAlloc(GPTR, DeviceInfoSize);
// Get default phonebook entry
lpRasEntry->dwSize = sizeof(RASENTRY);
if ((Ret = RasGetEntryProperties(NULL, "", lpRasEntry, &EntryInfoSize, lpDeviceInfo, &DeviceInfoSize)) != 0)
{
printf("RasGetEntryProperties failed with error %d\n", Ret);
return Ret;
}
// Validate new phonebook name "Testentry"
if ((Ret = RasValidateEntryName(NULL, APP_NAME)) != ERROR_SUCCESS)
{
printf("RasValidateEntryName failed with error %d\n", Ret);
if (Ret != ERROR_ALREADY_EXISTS)
return Ret;
}
LPRASDEVINFO ras_devices;
DWORD cb =sizeof(RASDEVINFO);
DWORD cbDevices = 0;
ras_devices = (LPRASDEVINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
if (NULL == ras_devices)
{
printf("HeapAlloc failed.\n");
return ERROR_OUTOFMEMORY;
}
ras_devices->dwSize = sizeof(RASDEVINFO);
if ((Ret = RasEnumDevices(ras_devices, &cb, &cbDevices)) != ERROR_SUCCESS)
{
printf("RasEnumDevices failed with error %d\n", Ret);
switch(Ret)
{
case ERROR_BUFFER_TOO_SMALL:
printf("buffer too small");
HeapFree(GetProcessHeap(), 0, (LPVOID)ras_devices);
ras_devices = (LPRASDEVINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
if (NULL == ras_devices)
{
printf("HeapAlloc failed.\n");
return ERROR_OUTOFMEMORY;
}
ras_devices->dwSize = sizeof(RASDEVINFO);
Ret = RasEnumDevices(ras_devices, &cb, &cbDevices);
if (ERROR_SUCCESS == Ret)
{
//fSuccess = TRUE;
}
else
{
printf("RasEnumDevices failed again: Error = %d\n", Ret);
return Ret;
//goto done;
}
break;
case ERROR_NOT_ENOUGH_MEMORY:
printf("ERROR_NOT_ENOUGH_MEMORY");
return Ret;
break;
case ERROR_INVALID_PARAMETER:
printf("ERROR_INVALID_PARAMETER");
return Ret;
break;
case ERROR_INVALID_USER_BUFFER:
printf("ERROR_INVALID_USER_BUFFER");
return Ret;
break;
}
}
DWORD dwVpnStrategy = 0;
char device_name_mask[5];
strcpy(device_name_mask, "");
gboolean preshared_key_valid = 0;
switch(connection_type)
{
case PPTP:
strcpy(device_name_mask, "PPTP");
dwVpnStrategy = VS_PptpOnly;
break;
case L2TP:
if (preshared_key == 0 || strlen(preshared_key) == 0)
{
printf("CRITICAL: preshared key not set.");
return 1;
}
else
{
preshared_key_valid = TRUE;
}
strcpy(device_name_mask, "L2TP");
dwVpnStrategy = VS_L2tpOnly;
break;
}
int i =0;
for (i = 0; i < cbDevices; i++)
{
RASDEVINFO r = ras_devices[i];
if (strstr(r.szDeviceName, device_name_mask))
{
break;
}
}
//lpRasEntry->dwfOptions |= RASEO_SpecificIpAddr;
//lpRasEntry->szLocalPhoneNumber = RASDT_Vpn;
lpRasEntry->dwfNetProtocols |= RASNP_Ip;
lpRasEntry->dwFramingProtocol = RASFP_Ppp;
lstrcpy(lpRasEntry->szDeviceType, RASDT_Vpn);
lstrcpy(lpRasEntry->szDeviceName, ras_devices[i].szDeviceName);
lstrcpy(lpRasEntry->szLocalPhoneNumber, server_address);
lpRasEntry->dwVpnStrategy = dwVpnStrategy; // VS_PptpOnly; VS_SstpOnly
if (preshared_key_valid)
{
L2TP_CONFIG_DATA* data = GlobalAlloc(GPTR, sizeof(L2TP_CONFIG_DATA));
lpRasEntry->dwfOptions2 |= RASEO2_UsePreSharedKey;
data->dwOffsetKey = 16;
memcpy((PBYTE)data + data->dwOffsetKey, preshared_key, strlen(preshared_key));
data->dwAuthType =L2TP_IPSEC_AUTH_PRESHAREDKEY;
RasSetCustomAuthData(NULL, APP_NAME, data, sizeof(L2TP_CONFIG_DATA));
}
if ((Ret = RasSetEntryProperties(NULL, APP_NAME, lpRasEntry, EntryInfoSize, lpDeviceInfo, DeviceInfoSize)) != 0)
{
printf("RasSetEntryProperties failed with error %d\n", Ret);
return Ret;
}
//if ((Ret = RasSetCredentials(NULL, lpRasEntry.))
}
I cant find where is buffer to fill for pre-shared key.
Following code works fine.
// l2tp
if (preshared_key_valid)
{
RASCREDENTIALS ras_cre_psk = {0};
ras_cre_psk.dwSize = sizeof(ras_cre_psk);
ras_cre_psk.dwMask = 0x00000010; //RASCM_PreSharedKey;
wcscpy(ras_cre_psk.szPassword, preshared_key);
if ((Ret = RasSetCredentials(NULL, APP_NAME, &ras_cre_psk, FALSE)))
{
printf("RasSetCredentials failed with error %d\n", Ret);
return Ret;
}
}

"bad packet length" error after updating to OpenSSL 0.9.8.zf

I was using OpenSSL version 0.9.8h in an Android project. I update it to the 0.9.8.zf version but now it doesn't work.
The two functions that highlight the problem are initialize_client_ctx and initialize_client_ctx. When I call SSL_connect I get an SSL_ERROR_SSL error value. By checking details I retrieve a "bad packet length" error (error:14092073:SSL routines:SSL3_GET_SERVER_HELLO:bad packet length).
The point in the code is indicated in a comment. The code works well with the previous version. I attach also a Wireshark capture file. Any ideas?
SSL_CTX *initialize_client_ctx(const char *keyfile, const char *certfile,
const char *password, int transport)
{
SSL_METHOD *meth = NULL;
X509 *cert = NULL;
SSL_CTX *ctx;
if (transport == IPPROTO_UDP) {
meth = DTLSv1_client_method();
} else if (transport == IPPROTO_TCP) {
meth = TLSv1_client_method();
} else {
return NULL;
}
ctx = SSL_CTX_new(meth);
if (ctx == NULL) {
//print ... Couldn't create SSL_CTX
return NULL;
}
if (password[0] != '\0') {
SSL_CTX_set_default_passwd_cb_userdata(ctx, (void *) password);
SSL_CTX_set_default_passwd_cb(ctx, password_cb);
}
if (tls_client_local_cn_name[0] != '\0') {
cert = _tls_set_certificate(ctx, tls_client_local_cn_name);
}
if (cert==NULL && certfile[0] != '\0') {
//print several warnings....
}
if (cert!=NULL)
{
X509_free(cert);
cert = NULL;
}
/* Load the CAs we trust */
{
char *caFile = 0, *caFolder = 0;
int fd = open(eXosip_tls_ctx_params.root_ca_cert, O_RDONLY);
if (fd >= 0) {
struct stat fileStat;
if (fstat(fd, &fileStat) < 0) {
} else {
if (S_ISDIR(fileStat.st_mode)) {
caFolder = eXosip_tls_ctx_params.root_ca_cert;
} else {
caFile = eXosip_tls_ctx_params.root_ca_cert;
}
}
close(fd);
}
{
int verify_mode = SSL_VERIFY_PEER;
SSL_CTX_set_verify(ctx, verify_mode, &verify_cb);
SSL_CTX_set_verify_depth(ctx, ex_verify_depth + 1);
}
}
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
SSL_OP_CIPHER_SERVER_PREFERENCE);
if(!SSL_CTX_set_cipher_list(ctx,"ALL")) {
//print ... set_cipher_list: cannot set anonymous DH cipher
SSL_CTX_free(ctx);
return NULL;
}
return ctx;
}
static int _tls_tl_ssl_connect_socket(struct socket_tab *sockinfo)
{
X509 *cert;
BIO *sbio;
int res;
if (sockinfo->ssl_ctx == NULL) {
sockinfo->ssl_ctx =
initialize_client_ctx(eXosip_tls_ctx_params.client.priv_key,
eXosip_tls_ctx_params.client.cert,
eXosip_tls_ctx_params.client.priv_key_pw,
IPPROTO_TCP);
sockinfo->ssl_conn = SSL_new(sockinfo->ssl_ctx);
if (sockinfo->ssl_conn == NULL) {
return -1;
}
sbio = BIO_new_socket(sockinfo->socket, BIO_NOCLOSE);
if (sbio == NULL) {
return -1;
}
SSL_set_bio(sockinfo->ssl_conn, sbio, sbio);
}
do {
struct timeval tv;
int fd;
fd_set readfds;
res = SSL_connect(sockinfo->ssl_conn);
res = SSL_get_error(sockinfo->ssl_conn, res);
if (res == SSL_ERROR_NONE) {
//printf... SSL_connect succeeded
break;
}
if (res != SSL_ERROR_WANT_READ && res != SSL_ERROR_WANT_WRITE) {
//<-- here there is a problem res == SSL_ERROR_SSL
//print ERR_reason_error_string(ERR_get_error()));
//print ERR_error_string(ERR_get_error(), NULL));
return -1;
}
tv.tv_sec = SOCKET_TIMEOUT / 1000;
tv.tv_usec = (SOCKET_TIMEOUT % 1000) * 1000;
//retry the connection
fd = SSL_get_fd(sockinfo->ssl_conn);
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
res = select(fd + 1, &readfds, NULL, NULL, &tv);
if (res < 0) {
//print error
return -1;
} else if (res > 0) {
//print...connetrion done!
} else {
//socket timeout, no data to read
return 1;
}
} while (!SSL_is_init_finished(sockinfo->ssl_conn));
if (SSL_is_init_finished(sockinfo->ssl_conn)) {
//print.. SSL_is_init_finished done
} else {
//print.. failed
}
cert = SSL_get_peer_certificate(sockinfo->ssl_conn);
if (cert != 0) {
int cert_err;
tls_dump_cert_info("tls_connect: remote certificate: ", cert);
cert_err = SSL_get_verify_result(sockinfo->ssl_conn);
if (cert_err != X509_V_OK) {
//print... Failed to verify remote certificate
tls_dump_verification_failure(cert_err);
if (eXosip_tls_ctx_params.server.cert[0] != '\0') {
X509_free(cert);
return -1;
} else if (cert_err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
&& cert_err != X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
&& cert_err != X509_V_ERR_CRL_HAS_EXPIRED
&& cert_err != X509_V_ERR_CERT_HAS_EXPIRED
&& cert_err != X509_V_ERR_CERT_REVOKED
&& cert_err != X509_V_ERR_CERT_UNTRUSTED
&& cert_err != X509_V_ERR_CERT_REJECTED) {
X509_free(cert);
return -1;
}
}
X509_free(cert);
} else {
//print .. No certificate received
/* X509_free is not necessary because no cert-object was created -> cert == NULL */
if (eXosip_tls_ctx_params.server.cert[0] == '\0') {
#ifdef ENABLE_ADH
/* how can we guess a user want ADH... specific APIs.. */
sockinfo->ssl_state = 3;
return 0;
#endif
}
return -1;
}
sockinfo->ssl_state = 3;
return 0;
}
SOLVED Thanks to Eric Tsui that helps me to figure out the problem. The 'hello' that I receive from the server in the handshake has zero length. To solve this I modified the file openssl/ssl/s3_clnt.c in the following way (toggling off the length control):
diff -ur ./s3_clnt.c ./original/s3_clnt.c
--- submodules/externals/openssl/ssl/s3_clnt.c 2015-06-29 14:59:56.723462992 +0200
+++ ../../opensslOrig/s3_clnt.c 2015-06-29 15:00:22.487464221 +0200
## -868,12 +868,14 ##
}
#endif
+#ifndef OPENSSL_NO_TLSEXT
if (p != (d + n)) {
/* wrong packet length */
al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_BAD_PACKET_LENGTH);
goto f_err;
}
+#endif
return (1);
f_err:

Cropping Square Video using FFmpeg

Updated
So I am trying to decode a mp4 file, crop the video into a square, and then re encode it back out to another mp4 file. This is my current code but there are a few issues with it.
One is that the video doesn't keep its rotation after the video has been re encoded
Second is that the frames get outputted in a very fast video file that is not the same length as the original
Third is that there is no sound
Lastly and most importantly is do I need AVFilter to do the frame cropping or can it just be done per frame as a resize of the frame and then encoded back out.
const char *inputPath = "test.mp4";
const char *outPath = "cropped.mp4";
const char *outFileType = "mp4";
static AVFrame *oframe = NULL;
static AVFilterGraph *filterGraph = NULL;
static AVFilterContext *crop_ctx = NULL;
static AVFilterContext *buffersink_ctx = NULL;
static AVFilterContext *buffer_ctx = NULL;
int err;
int crop_video(int width, int height) {
av_register_all();
avcodec_register_all();
avfilter_register_all();
AVFormatContext *inCtx = NULL;
// open input file
err = avformat_open_input(&inCtx, inputPath, NULL, NULL);
if (err < 0) {
printf("error at open input in\n");
return err;
}
// get input file stream info
err = avformat_find_stream_info(inCtx, NULL);
if (err < 0) {
printf("error at find stream info\n");
return err;
}
// get info about video
av_dump_format(inCtx, 0, inputPath, 0);
// find video input stream
int vs = -1;
int s;
for (s = 0; s < inCtx->nb_streams; ++s) {
if (inCtx->streams[s] && inCtx->streams[s]->codec && inCtx->streams[s]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
vs = s;
break;
}
}
// check if video stream is valid
if (vs == -1) {
printf("error at open video stream\n");
return -1;
}
// set output format
AVOutputFormat * outFmt = av_guess_format(outFileType, NULL, NULL);
if (!outFmt) {
printf("error at output format\n");
return -1;
}
// get an output context to write to
AVFormatContext *outCtx = NULL;
err = avformat_alloc_output_context2(&outCtx, outFmt, NULL, NULL);
if (err < 0 || !outCtx) {
printf("error at output context\n");
return err;
}
// input and output stream
AVStream *outStrm = avformat_new_stream(outCtx, NULL);
AVStream *inStrm = inCtx->streams[vs];
// add a new codec for the output stream
AVCodec *codec = NULL;
avcodec_get_context_defaults3(outStrm->codec, codec);
outStrm->codec->thread_count = 1;
outStrm->codec->coder_type = AVMEDIA_TYPE_VIDEO;
if(outCtx->oformat->flags & AVFMT_GLOBALHEADER) {
outStrm->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
outStrm->codec->sample_aspect_ratio = outStrm->sample_aspect_ratio = inStrm->sample_aspect_ratio;
err = avio_open(&outCtx->pb, outPath, AVIO_FLAG_WRITE);
if (err < 0) {
printf("error at opening outpath\n");
return err;
}
outStrm->disposition = inStrm->disposition;
outStrm->codec->bits_per_raw_sample = inStrm->codec->bits_per_raw_sample;
outStrm->codec->chroma_sample_location = inStrm->codec->chroma_sample_location;
outStrm->codec->codec_id = inStrm->codec->codec_id;
outStrm->codec->codec_type = inStrm->codec->codec_type;
if (!outStrm->codec->codec_tag) {
if (! outCtx->oformat->codec_tag
|| av_codec_get_id (outCtx->oformat->codec_tag, inStrm->codec->codec_tag) == outStrm->codec->codec_id
|| av_codec_get_tag(outCtx->oformat->codec_tag, inStrm->codec->codec_id) <= 0) {
outStrm->codec->codec_tag = inStrm->codec->codec_tag;
}
}
outStrm->codec->bit_rate = inStrm->codec->bit_rate;
outStrm->codec->rc_max_rate = inStrm->codec->rc_max_rate;
outStrm->codec->rc_buffer_size = inStrm->codec->rc_buffer_size;
const size_t extra_size_alloc = (inStrm->codec->extradata_size > 0) ?
(inStrm->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE) :
0;
if (extra_size_alloc) {
outStrm->codec->extradata = (uint8_t*)av_mallocz(extra_size_alloc);
memcpy( outStrm->codec->extradata, inStrm->codec->extradata, inStrm->codec->extradata_size);
}
outStrm->codec->extradata_size = inStrm->codec->extradata_size;
AVRational input_time_base = inStrm->time_base;
AVRational frameRate = {25, 1};
if (inStrm->r_frame_rate.num && inStrm->r_frame_rate.den
&& (1.0 * inStrm->r_frame_rate.num / inStrm->r_frame_rate.den < 1000.0)) {
frameRate.num = inStrm->r_frame_rate.num;
frameRate.den = inStrm->r_frame_rate.den;
}
outStrm->r_frame_rate = frameRate;
outStrm->codec->time_base = inStrm->codec->time_base;
outStrm->codec->pix_fmt = inStrm->codec->pix_fmt;
outStrm->codec->width = width;
outStrm->codec->height = height;
outStrm->codec->has_b_frames = inStrm->codec->has_b_frames;
if (!outStrm->codec->sample_aspect_ratio.num) {
AVRational r0 = {0, 1};
outStrm->codec->sample_aspect_ratio =
outStrm->sample_aspect_ratio =
inStrm->sample_aspect_ratio.num ? inStrm->sample_aspect_ratio :
inStrm->codec->sample_aspect_ratio.num ?
inStrm->codec->sample_aspect_ratio : r0;
}
avformat_write_header(outCtx, NULL);
filterGraph = avfilter_graph_alloc();
if (!filterGraph) {
printf("could not open filter graph");
return -1;
}
AVFilter *crop = avfilter_get_by_name("crop");
AVFilter *buffer = avfilter_get_by_name("buffer");
AVFilter *buffersink = avfilter_get_by_name("buffersink");
char args[512];
snprintf(args, sizeof(args), "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",
width, height, inStrm->codec->pix_fmt,
inStrm->codec->time_base.num, inStrm->codec->time_base.den,
inStrm->codec->sample_aspect_ratio.num, inStrm->codec->sample_aspect_ratio.den);
err = avfilter_graph_create_filter(&buffer_ctx, buffer, NULL, args, NULL, filterGraph);
if (err < 0) {
printf("error initializing buffer filter\n");
return err;
}
err = avfilter_graph_create_filter(&buffersink_ctx, buffersink, NULL, NULL, NULL, filterGraph);
if (err < 0) {
printf("unable to create buffersink filter\n");
return err;
}
snprintf(args, sizeof(args), "%d:%d", width, height);
err = avfilter_graph_create_filter(&crop_ctx, crop, NULL, args, NULL, filterGraph);
if (err < 0) {
printf("error initializing crop filter\n");
return err;
}
err = avfilter_link(buffer_ctx, 0, crop_ctx, 0);
if (err < 0) {
printf("error linking filters\n");
return err;
}
err = avfilter_link(crop_ctx, 0, buffersink_ctx, 0);
if (err < 0) {
printf("error linking filters\n");
return err;
}
err = avfilter_graph_config(filterGraph, NULL);
if (err < 0) {
printf("error configuring the filter graph\n");
return err;
}
printf("filtergraph configured\n");
for (;;) {
AVPacket packet = {0};
av_init_packet(&packet);
err = AVERROR(EAGAIN);
while (AVERROR(EAGAIN) == err)
err = av_read_frame(inCtx, &packet);
if (err < 0) {
if (AVERROR_EOF != err && AVERROR(EIO) != err) {
printf("eof error\n");
return 1;
} else {
break;
}
}
if (packet.stream_index == vs) {
//
// AVPacket pkt_temp_;
// memset(&pkt_temp_, 0, sizeof(pkt_temp_));
// AVPacket *pkt_temp = &pkt_temp_;
//
// *pkt_temp = packet;
//
// int error, got_frame;
// int new_packet = 1;
//
// error = avcodec_decode_video2(inStrm->codec, frame, &got_frame, pkt_temp);
// if(error < 0) {
// LOGE("error %d", error);
// }
//
// // if (error >= 0) {
//
// // push the video data from decoded frame into the filtergraph
// int err = av_buffersrc_write_frame(buffer_ctx, frame);
// if (err < 0) {
// LOGE("error writing frame to buffersrc");
// return -1;
// }
// // pull filtered video from the filtergraph
// for (;;) {
// int err = av_buffersink_get_frame(buffersink_ctx, oframe);
// if (err == AVERROR_EOF || err == AVERROR(EAGAIN))
// break;
// if (err < 0) {
// LOGE("error reading buffer from buffersink");
// return -1;
// }
// }
//
// LOGI("output frame");
err = av_interleaved_write_frame(outCtx, &packet);
if (err < 0) {
printf("error at write frame");
return -1;
}
//}
}
av_free_packet(&packet);
}
av_write_trailer(outCtx);
if (!(outCtx->oformat->flags & AVFMT_NOFILE) && outCtx->pb)
avio_close(outCtx->pb);
avformat_free_context(outCtx);
avformat_close_input(&inCtx);
return 0;
}
It looks like you are looking for vf_crop.
The CropContext contains a x, y, w, and h, which should be what you need to crop a video to a specific width and height.

Resources