Hello All,
I can not connect to a HTTPS server of WebServices. (
https://hnfe.sefaz.es.gov.br/Nfe/wsdl/nfeStatusServico.wsdl)
The error occurs when the function SSL_read() is calling, returning 0 and
SSL_get_error () equals SSL_ERROR_ZERO_RETURN.
The problem is not the certificates, because when installing in firefox/IE
to view the WSDL in the browser, its ok.
Using ethereal, there was 1 extra handshake between this sample and
firefox/IE.
I created a simple program for example that reproduces the problem.
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#define DEFAULT_FAMILY AF_INET
#define DEFAULT_SOCKTYPE SOCK_STREAM
#define DEFAULT_PORT "443"
static unsigned char dh512_p[]={
0xDA,0x58,0x3C,0x16,0xD9,0x85,0x22,0x89,0xD0,0xE4,0xAF,0x75,
0x6F,0x4C,0xCA,0x92,0xDD,0x4B,0xE5,0x33,0xB8,0x04,0xFB,0x0F,
0xED,0x94,0xEF,0x9C,0x8A,0x44,0x03,0xED,0x57,0x46,0x50,0xD3,
0x69,0x99,0xDB,0x29,0xD7,0x76,0x27,0x6B,0xA2,0xD3,0xD4,0x12,
0xE2,0x18,0xF4,0xDD,0x1E,0x08,0x4C,0xF6,0xD8,0x00,0x3E,0x7C,
0x47,0x74,0xE8,0x33,
};
static unsigned char dh512_g[]={
0x02,
};
SOCKET sock = INVALID_SOCKET;
int chkSSL(int AError, SSL *s, BIO *bio_e);
DH *GetDH512(void);
int myReceiveLine( SSL *ssl, char *data, int maxDataLen, int timeOut);
bool WaitForReceive(long secs,long uSecs);
//------------------------------------------------------------------
int main(int argc, char **argv)
{
ADDRINFO Hints, *AddrInfo = NULL, *AI;
WSADATA wsaData;
int nFamily = DEFAULT_FAMILY;
int nSockType = DEFAULT_SOCKTYPE;
char szRemoteAddrString[128];
char szRemoteName[64];
char *szPort = DEFAULT_PORT;
char scommand[512];
// VARIAVEIS SSL
int nServerVerify;
int nServerSessionIdContext;
char szCertificate[256];
SSL *ssl=NULL;
SSL_CTX *ctx=NULL;
SSL_METHOD *meth=NULL;
BIO *sslBio;
BIO *sslErr;
if(argc < 5){
printf("Usage:\n sample <HOST> <PORT> <CERTPEMPATH> <PASSPHRASE>");
return(0);
}
if(WSAStartup(MAKEWORD(2,2), &wsaData)){
printf("ERROR: WSAStartup failed");
goto Cleanup;
}
strncpy(szRemoteName, argv[1], sizeof(szRemoteName));
szRemoteName[63] = '\0';
printf("Communicating with server - %hs\r\n", szRemoteName);
printf("Communicating with port - %hs\r\n", szPort);
memset(&Hints, 0, sizeof(Hints));
Hints.ai_family = nFamily;
Hints.ai_socktype = nSockType;
if(getaddrinfo(szRemoteName, szPort, &Hints, &AddrInfo) != 0){
printf("ERROR: Couldn't get resolve the server name/address!");
goto Cleanup;
}
AI = AddrInfo;
if (AI == NULL) {
printf("ERROR: Unable to connect to any of the server's
addresses!");
goto Cleanup;
}
if(AI->ai_family == DEFAULT_FAMILY) {
sock = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol);
if (sock != INVALID_SOCKET) {
if(connect(sock, AI->ai_addr, AI->ai_addrlen) == SOCKET_ERROR) {
// Connect failed, let's close this socket and try again on
the next address in the list
printf("FAIL: Failed to connect");
closesocket(sock);
}
}
if (getnameinfo(AI->ai_addr, AI->ai_addrlen,
szRemoteAddrString, sizeof(szRemoteAddrString), NULL, 0,
NI_NUMERICHOST) != 0)
strcpy(szRemoteAddrString, "");
printf("Succeeded Conected with the server: %hs",
szRemoteAddrString);
}
else
printf("INVALID: Failed to connect with %hs", AI->ai_addr->sa_data);
nServerVerify = SSL_VERIFY_NONE;
nServerSessionIdContext = 1;
//-----------START INITIALIZE HANDSHAKE--------------------------
SSL_load_error_strings();
SSL_library_init();
sslErr = BIO_new_file("ssl.log","a");
meth=SSLv3_client_method();
ctx = SSL_CTX_new(meth);
SSL_CTX_set_quiet_shutdown(ctx,1);
int nOffProtocol = 0;
nOffProtocol |= SSL_OP_NO_SSLv2;
nOffProtocol |= SSL_OP_NO_TLSv1;
SSL_CTX_set_options(ctx, nOffProtocol);
SSL_CTX_sess_set_cache_size(ctx, 2);
SSL_CTX_set_session_id_context(ctx, (const unsigned
char*)&nServerSessionIdContext, sizeof(nServerSessionIdContext));
strncpy(szCertificate, argv[3], sizeof(szCertificate));
szRemoteName[255] = '\0';
if( SSL_CTX_use_certificate_file(ctx, szCertificate,
SSL_FILETYPE_PEM) <= 0){
printf( "ERROR: unable to get certificate from '%s'\n",
argv[3]);
ERR_print_errors(sslErr);
goto Cleanup;
}
SSL_CTX_set_default_passwd_cb_userdata(ctx, argv[4]);
if (SSL_CTX_use_PrivateKey_file(ctx, szCertificate,
SSL_FILETYPE_PEM) <= 0){
printf("ERROR: unable to get private key from '%s'\n",argv[3]);
ERR_print_errors(sslErr);
goto Cleanup;
}
if (!SSL_CTX_check_private_key(ctx)){
printf( "ERROR: Private key does not match the certificate
public key\n");
goto Cleanup;
}
SSL_CTX_set_default_passwd_cb_userdata(ctx, NULL);
if ((!SSL_CTX_load_verify_locations(ctx, szCertificate, 0)) ||
(!SSL_CTX_set_default_verify_paths(ctx))){
printf( "ERROR: not load verify locations\n");
goto Cleanup;
}
/* DH OPTIONS */
DH *dh = GetDH512();
BIO_flush(sslErr);
SSL_CTX_set_tmp_dh(ctx, dh);
DH_free(dh);
ssl = SSL_new(ctx);
chkSSL(SSL_clear(ssl),ssl,sslErr);
sslBio = BIO_new_socket(sock,BIO_NOCLOSE);
SSL_set_bio(ssl, sslBio, sslBio);
//------------END INITIALIZE HANDSHAKE--------------------------
SSL_set_connect_state(ssl);
int retCon = 0;
retCon = chkSSL(SSL_connect(ssl), ssl, sslErr);
if ( retCon < 0){
printf("ERROR: Failed to connect with SSL");
goto Cleanup;
}
if (SSL_ctrl(ssl,SSL_CTRL_GET_FLAGS,0,NULL) & TLS1_FLAGS_TLS_PADDING_BUG
){
printf( "ERROR: Peer has incorrect TLSv1 block padding\n");
goto Cleanup;
}
// ops, test program....
strncpy(scommand,
"GET /Nfe/wsdl/nfeStatusServico.wsdl HTTP/1.1\r\nHost:
hnfe.sefaz.es.gov.br\r\nConnection: Keep-Alive\r\nAccept: */*\r\n",
sizeof(szCertificate));
scommand[511] = '\0';
int iResult = send( sock, scommand, (int)strlen(scommand), 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
goto Cleanup;
}
char pTemp[16384];
iResult = myReceiveLine( ssl, pTemp, 2048, 120 );
if( iResult < 12 ){
printf("ERROR: Invalid HTTP Connection");
goto Cleanup;
};
// HTTP/1.0 200 OK
// ops!! receive ZERO
Cleanup:
BIO_free(sslErr);
BIO_free(sslBio);
closesocket(sock);
WSACleanup();
SSL_shutdown(ssl);
return(1);
}
//=================================================================================
bool WaitForReceive(long secs,long uSecs)
{
fd_set readSet;
struct timeval tv;
tv.tv_sec = secs;
tv.tv_usec =uSecs;
if( sock==INVALID_SOCKET )
return false;
FD_ZERO(&readSet);
FD_SET(sock,&readSet);
// Wait up to the specified time to see if data is avail
if( select(sock+1,&readSet,NULL,NULL,&tv) != 1)
return false;
return true;
}
int myReceive( SSL *ssl, void *data, unsigned int len, int flags, int
timeOut )
{
int rcv = 0;
if(timeOut > 0)
if( !SSL_pending(ssl) && !WaitForReceive(timeOut,0) )
return 0;
do
{
int tmp = SSL_read(ssl,(char *)data+rcv, len-rcv);
rcv += tmp;
int x = SSL_get_error(ssl, tmp);
switch (x)
{
case SSL_ERROR_NONE:
//#ifdef CHARSET_EBCDIC ascii2ebcdic(buf,buf,i); #endif
break;
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_READ:
rcv = 0;
tmp = SSL_peek(ssl, (char *)data+rcv, len-rcv);
if (tmp > 0)
{
int tmp = SSL_read(ssl,(char *)data+rcv, len-rcv);
rcv += tmp;
}
break;
case SSL_ERROR_WANT_X509_LOOKUP:
break;
case SSL_ERROR_SYSCALL:
case SSL_ERROR_SSL:
rcv = -1;
break;
case SSL_ERROR_ZERO_RETURN:
rcv = -1;
break;
}
} while (rcv >= 0 && ((len-rcv) >0) && SSL_pending(ssl));
return rcv;
}
int myReceiveLine( SSL *ssl, char *data, int maxDataLen, int timeOut)
{
int rt, count = 0;
char *dataPtr = NULL;
memset(data, 0, maxDataLen);
maxDataLen--;
while (maxDataLen > 0)
{
dataPtr = &data[count];
rt = myReceive(ssl,(char *) dataPtr, 1, 0, timeOut);
if (rt == 1)
{
maxDataLen--;
count++;
if (*dataPtr == '\r')
{
dataPtr = &data[count];
rt = myReceive(ssl,(char *) dataPtr, 1, 0, 0);
if (rt == 1)
{
maxDataLen--;
count++;
if (*dataPtr == '\n')
return count;
}
else if (rt <= 0)
return count;
}
}
else if (rt <= 0)
return count;
}
return count;
}
DH * GetDH512(void)
{
DH *dh = NULL;
if ((dh=DH_new()) == NULL)
return(NULL);
dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
if ((dh->p == NULL) || (dh->g == NULL))
return(NULL);
return(dh);
}
int ShowSSLError(int AError, SSL *s, BIO *bio_e)
{
char cAux[1024];
int x = SSL_get_error(s, AError);
if( x != 5 )
{
printf("**** SSL erro = %d\n", AError);
printf(" SSL code = %d\n", x);
ERR_error_string(x, cAux);
printf(" %s\n", cAux);
};
return AError;
}
int chkSSL(int AError, SSL *s, BIO *bio_e)
{
if (AError < 0)
ShowSSLError(AError, s, bio_e);
return AError;
}
thanks in advanced!!
Ricardo