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

Reply via email to