I have a test program that opens a windows socket to test.authorize.net in an effort to process a card-present test. The data are detailed with highlights to show the various parts of the SSL post. Unfortunately, the screen capture images in my Rich Text document twill not paste into this Rich Text document. The comments associated with the screen captures are below. They explain the sequence.
If the actual data or the test program code would be helpful, I could email them. Do not see a way to attach them to this post.
Whatever the C# demo program is doing, I cannot seem to capture it on the LAN with wireshark. I do not observe any activity on 64.94.118.151.
HERE IS WHERE THE SOCKET CONNECTION IS OPENED SUCCESSFULLY:
HERE IS THE ACK FROM AUTHORIZE.NET:
HERE IS SOME INITIAL CONTROL PROTOCOL TO PORT 443 PRIOR TO THE SSL POST:
HERE IS THE INTERNET PROTOCOL PORTION OF THE SSL MESSAGE:
HERE IS THE PROTOCOL DATA HIGHLIGHTED:
FINALLY HERE IS THE SECURE SOCKETS LAYER HIGHLIGHTED:
AT SOME POINT LATER, I SEND THE FOLLOWING MESSAGE TO AUTHORIZE.NET WHICH I SUSPECT CLOSES THE CONNECTION WHEN THE PROGRAM TIMES OUT OR IF I END THE DEBUG:
06-25-2013 12:12 AM
Can you clarify what you are actually asking here? I'm assuming that some code is failing to connect to us, but it is unclear if you are using our sample code, our SDK, or some custom code. It's also not clear what error you are receiving.
06-28-2013 02:29 PM
It seems that I am not posting to https but http, thus there is no response from authorize .net. I have been search for a clear-cut way to turn on SSL in a c++ environment. I've seen some examples and there are several libraries out there which obscure what needs to be done to get the certificate negotiation complete. I'm seeing the problem... but running out of time. For now, I'm trying to figure out how to enable SSL.
#include
<string>
#include
<iostream>
using
std::string;
using
namespace std; //needed?
#define
WIN32_LEAN_AND_MEAN // don't know what this is...
#include
<winsock2.h>
#include
<windows.h>
#include
<ws2tcpip.h>
#include
<stdlib.h>
#include
<stdio.h>
#include
<string.h>
#define
DEFAULT_PORT "443"
#define
DEFAULT_BUFLEN 512
string authnet_server=
"test.authorize.net";
string authnet_path=
"/gateway/transact.dll";
//string authnet_server="developer.authorize.net";
//string authnet_path="/tools/paramdump/index.php";
//We create our WSADATA structure which we will use to gather information from the Winsock library
//in this computer. wVers will be used for our version number that we want.
//iError will be used to check for any errors and display a message box if there is any trouble.
int
main(){
WSADATA t_wsa;
// WSADATA structure
WORD wVers;
// version numberint iError; // error number
//____________________________________________________________________
// from getaddrinfo example
DWORD dwRetval;
inti = 1;
structaddrinfo *result = NULL;
structaddrinfo *ptr = NULL;
structaddrinfo hints;
struct sockaddr_in *sockaddr_ipv4; //defines a structure with pointer to socketaddr.// struct sockaddr_in6 *sockaddr_ipv6;
// LPSOCKADDR sockaddr_ip;
// char ipstringbuffer[46];
DWORD ipbufferlength = 46;
//_________________________________________________________________
printf_s(
"Print test/n"); //print something...
// cannot get message box to work correctly?...
::MessageBox(NULL, (LPCTSTR)
"message 1", (LPCTSTR)"message 2", MB_OK);
// MessageBox(NULL, ("Open the message box "),("message"),MB_OK|MB_SYSTEMMODAL);
// ::MessageBox(NULL, ("message 1"), ("message 2"), MB_OK);
wVers = MAKEWORD(2, 2);
// Set the version number to 2.2
iError = WSAStartup(wVers, &t_wsa);
// Start the WSADATAif(iError != NO_ERROR || iError == 1)
{
MessageBox(NULL, (LPCTSTR)
"Error at WSAStartup()", (LPCTSTR)"Client::Error", MB_OK|MB_ICONERROR);
WSACleanup();
return0;
}
/* Correct version? */if(LOBYTE(t_wsa.wVersion) != 2 || HIBYTE(t_wsa.wVersion) != 2)
{
MessageBox(NULL, (LPCTSTR)
"Error at WSAStartup()", (LPCTSTR)"Client::Error", MB_OK|MB_ICONERROR);
WSACleanup();
return0;
}
//Now let's create our sClient SOCKET. Using socket() function we establish a TCP socket with the standard settings.
//Refer to the MSDN library for more options. We check for any errors and we continue.
SOCKET sClient;
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sClient == INVALID_SOCKET || iError == 1)
{
MessageBox(NULL, (LPCTSTR)
"Invalid Socket!", (LPCTSTR)"Client::Error", MB_OK|MB_ICONERROR);
WSACleanup();
return0;
}
//We establish a SOCKADDR_IN which is a structure used to set the settings of this socket.
//We first memset the sinClient to its own size.
//Then we use the server IP
//(if the server is located on another IP just change the strcpy function, 127.0.0.1 means yourself).
//make sure the server runs at this IP on your computer before you try and test the program.
//how do we set up the IP address & port using getaddrinfo function?
// e.g. set it in a string as xxx.xxx.xxx.xxx rather than the name?
charcPORT[50];
charcIP[50];
ZeroMemory(&hints,
sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
strcpy_s (cIP,
"test.authorize.net"); //??? correct???
// strcpy_s (cIP, "developer.authorize.net"); //??? correct???
strcpy_s (cPORT,
"443");
dwRetval = getaddrinfo(cIP,cPORT,&hints,&result);
if(dwRetval != 0)
{printf(
"getaddrinfo failed error: %d\n", dwRetval);
WSACleanup();
return1;
}
for(ptr=result; ptr != NULL; ptr=ptr->ai_next)
{
printf(
"getaddrinfo response %d\n", i++);
printf(
"\tFlags: 0x%x\n", ptr->ai_flags);
printf(
"\tFamily: ");
switch(ptr->ai_family)
{
case AF_UNSPEC: printf("Unspecified\n");break;
case AF_INET: printf("AF_INET (IPvc4)\n");
sockaddr_ipv4 = (
structsockaddr_in *) ptr->ai_addr;
printf(
"\tIPv4 address %s\n", inet_ntoa(sockaddr_ipv4->sin_addr));
break;
}
}
// we have the domain address converted to IP address.
SOCKADDR_IN sinClient;
memset(&sinClient, 0,
sizeof(sinClient));
sinClient.sin_family = AF_INET;
sinClient.sin_addr.s_addr = inet_addr(inet_ntoa(sockaddr_ipv4->sin_addr));
// Where to start server?
sinClient.sin_port = htons(443);
// Port
/*
Be sure to also add the sin_family, sin_addr being the IP we just set, and
the htons(443) which means we want to set the socket to port 443.
We connect our socket using our new information to that port and IP.
We check for errors and if everything is fine, we set a success message such as "You are connected!":
*/
// < put in the stuff for ssl to be activated....>
// if(connect(sClient, (LPSOCKADDR)&sinClient, sizeof(sinClient)) == SOCKET_ERROR)
if(connect(sClient, (LPSOCKADDR)&sinClient, sizeof(sinClient)) == SOCKET_ERROR)
{
/* failed at starting server */
MessageBox(NULL, (LPCTSTR)
"Could not connect to the server!", (LPCTSTR)"Client::Error", MB_OK|MB_ICONERROR);
WSACleanup();
return0;
}
// Now we can send/recv data!int iRet;
// char cBuffer[600]; //not used, must have been "buffer"?
MessageBox(NULL, (LPCTSTR)
"You are connected! Sending a message to the server (less than 599 characters)!", (LPCTSTR)"Client::Server", MB_OK|MB_ICONEXCLAMATION);
//Now lets create a message for authorize.net
// set up the credit card data:
charql[20];
std::string querystring =
"x_cpversion=1.0";
querystring +=
"&x_login=25Rm5bXr3";
querystring +=
"&x_tran_key=7C64yVEz7rX56658";
querystring +=
"x_type=AUTH_CAPTURE";
querystring +=
"&x_market_type=2";
// querystring += "&x_device_type=4";
querystring +=
"&x_cpversion=1.0";
querystring +=
"&x_response_format=1";
querystring +=
"&x_track1=%B4111111111111111^CARDUSER/JOHN^1803101000000000020000831000000?";
querystring +=
"&x_amount=1.99";
querystring +=
"&x_description=CPP Transaction";
intisize = (querystring.length())-1;
printf(
"\nlength = %d", isize,"\n");
_itoa_s (isize, ql, 10);
//gives wrong result....
printf(
"\nql = %s",ql);
// std::string buffer[512];
// char * Pointer = buffer.c_str();
std::string buffer =
"POST ";
buffer += authnet_path.c_str();
buffer +=
" HTTP/1.0\n";
buffer +=
"Host: ";
buffer += authnet_server.c_str();
buffer +=
"\n";
buffer +=
"Content-Type: application/x-www-form-urlencoded\n";
buffer +=
"Content-Length: ";
buffer += ql;
//querystring.length();
buffer +=
"\n\n";
buffer += (querystring.c_str());
printf(
"\nquerystring length = %d",querystring.length(),"\n\n");
printf_s(
"\nbuffer dump:\n");
printf(buffer.c_str());
printf(
"\n");
printf (
"buffer length = %d", buffer.length(), "\n\n");
//We use send() function to send that message to our socket!
iRet = send(sClient, buffer.c_str(), buffer.length(), 0);
if(iRet == SOCKET_ERROR)
{
MessageBox(NULL, (LPCTSTR)
"Could not send data!", (LPCTSTR)"Client::Error", MB_OK|MB_ICONERROR);
WSACleanup();
return0;
}
/*
Now we create our cServerMessage buffer which will contain server responses
whenever we receive any information!
Using our while loop we continuously use "recv()" to get any messages the server might be sending us.
If bytes becomes SOCKET_ERROR in our loop, it means we had an error and
should display the appropriate error message.
If the bytes received is 0 or WSAECONNRESET,
we know that we have disconnected and therefore
we should display an error and shut down the program.
*/
intbytes;
bytes = SOCKET_ERROR;
char*cServerMessage;
cServerMessage =
newchar[600];
while
(bytes = recv(sClient, cServerMessage, 599, 0))
{
if(bytes == SOCKET_ERROR)
{
charcError[500];
sprintf_s(cError,
"Connection failed, WINSOCK error code: %d", WSAGetLastError());
MessageBox(NULL, (LPCTSTR)cError, (LPCTSTR)
"Client::Error", MB_OK|MB_ICONERROR);
closesocket(sClient);
// Shutdown Winsock
WSACleanup();
return0;
}
if(bytes == 0 || bytes == WSAECONNRESET)
{
MessageBox(NULL, (LPCTSTR)
"Connection Disconnected!", (LPCTSTR)"Client::Error", MB_OK|MB_ICONERROR);
closesocket(sClient);
// Shutdown Winsock
WSACleanup();
return0;
}
if(bytes < 1)
{
Sleep(300);
continue;
}
/*
If everything goes well we display the message that we receive from the server
and we use Sleep to make sure our program doesn't waste too much CPU resources.
*/
MessageBox(NULL, (LPCTSTR)cServerMessage, (LPCTSTR)
"Client::Server Response", MB_OK);
delete[] cServerMessage;
cServerMessage =
newchar[600];
Sleep(100);
// Don't consume too much CPU power.
}
//This section is the end of our program and our clean up in case our messages are finished
//or we are broken out of the receiving loop. Of course there is no proper way to exit this program
//except via Ctrl+Alt+Delete and ending the process.
//The reason being we don't want to over complicate this code for a simple exit method.
//However, it is standard to code the ESC button to exit or create a GUI for this program using the Win32 C++ API.
delete[] cServerMessage;
// Cleanup
closesocket(sClient);
// Shutdown Winsock//We use WSACleanup() to make sure we don't have leaks or crashes.
WSACleanup();
return0;
}
06-30-2013 08:55 PM
During the SSL handshake, does the Authorize.net server require the client to provide a certificate?
06-30-2013 09:29 PM
During the SSL handshake, does the Authorize.net server require the client to provide a certificate?
no. It could be call from an application.
07-01-2013 04:50 AM