OpenSSL openwrt failed socket bind
<p>I am running openwrt on Dragino Yun. My wish is to run an openssl server on the Dragino that will be used for transferring some (not so large amounts of) data. However, after starting the server and loading the certificates, a call to <code>BIO_do_accept()</code> returns the value &lt;= 0, indicating a failed bind. The port I am trying to bind is 5354, but I tried 8081, 8080, 443 even.</p>

<p>The error message I get from <code>ERR_print_errors_fp</code> is:</p>

<pre><code>1998677064:error:0200407C:lib(2):func(4):reason(124):NA:0:port='5354'
1998677064:error:20069076:lib(32):func(105):reason(118):NA:0:
</code></pre>

<p>Could anybody explain why is my program unable to bind? I have tested it on Ubuntu - this is why I haven't posted any code - (the problem I have is with a cross-compiled version), OpenSSL version <code>OpenSSL 1.0.1f 6 Jan 2014</code> and, on Dragino, OpenSSL version is: <code>OpenSSL 1.0.1h 5 Jun 2014</code>. 
Also, Dragino version (from the banner) is <code>Dragino-v2 common-2.0.5</code></p>

<p>I tried using s_server and the result is following:</p>

<pre><code>root@dragino-70decb:~/certificates# openssl s_server -key server.key.pem -cert server.cert.pem -accept 8081
Enter pass phrase for server.key.pem:
Using default temp DH parameters
ACCEPT
</code></pre>

<p>which, when s_client is used, produced some communication, thus the socket bind was ok.</p>

<p>So, what is the problem and how do I make this work properly?
I tried Googling the error message but to no avail.</p>

<p>Also, I altered iptables to have ACCEPT default policy on INPUT, FORWARD and OUTPUT chains.</p>

<p>EDIT: Adding the code.</p>

<p>common.h:</p>

<pre><code>#define PORT "5354"
#define SERVER "localhost"
#define CLIENT "localhost"
#define CIPHER_LIST "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"

#define SSL_METHOD_ SSLv23_method()
#define SEED_PRNG_() seed_prng(30)
#define SSL_CTX_FLAGS_ SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION
#define DEFAULT_DEPTH_ 4
#define DATA_SIZE_ 256


void init_OpenSSL(void) ;
int seed_prng(int bytes) ;
int verify_callback(int ok, X509_STORE_CTX *store) ;

int write_to_SSL(SSL *ssl, const char* msg, int length) ;
int read_from_SSL(SSL *ssl, char* msg, int length) ;
</code></pre>

<p>common.c:</p>

<pre><code>#include "common.h"
void init_OpenSSL(void)
{
    if (!SSL_library_init())
    {
        fprintf(stderr, "** OpenSSL initialization failed!\n");
        exit(-1);
    }
    //Loads error strings for various SSL functions
    SSL_load_error_strings();
}

//Not sure if this is good idea
int seed_prng(int bytes)
{
    //Seeds PRNG (pseudo random number generator) with the contents of the /dev/urandom file
    if (!RAND_load_file("/dev/urandom", bytes))
    {
        return 0;
    }

    return 1;
}

int verify_callback(int ok, X509_STORE_CTX *store)
{
    char data[DATA_SIZE_];
    if (!ok)
    {
        X509 *cert = X509_STORE_CTX_get_current_cert(store);
        int depth = X509_STORE_CTX_get_error_depth(store);
        int err = X509_STORE_CTX_get_error(store);
        fprintf(stderr, "-Error with certificate at depth: %i\n", depth);
        X509_NAME_oneline(X509_get_issuer_name(cert), data, DATA_SIZE_);
        fprintf(stderr, " issuer = %s\n", data);
        X509_NAME_oneline(X509_get_subject_name(cert), data, DATA_SIZE_);
        fprintf(stderr, " subject = %s\n", data);
        fprintf(stderr, " err %i:%s\n", err,
        X509_verify_cert_error_string(err));
    }
    return ok;
}


int write_to_SSL(SSL *ssl, const char* msg, int length)
{
    int writtenbytes = 0;
    int err = 0;

    while(err &gt;= 0 &amp;&amp; writtenbytes &lt; length)
    {
        err = SSL_write(ssl, msg + writtenbytes, length - writtenbytes);
        if(err &lt; 0)
        {
            return err;
        }
        else
        {
            writtenbytes += err;
        }
    }

    return writtenbytes ;
}
int read_from_SSL(SSL *ssl, char* msg, int length)
{
    int err = 0, readbytes = 0;

    while(err &gt; 0 &amp;&amp; readbytes &lt; length)
    {
        err = SSL_read(ssl, msg + readbytes, length - readbytes);

        if(err &lt; 0)
        {
            return err;
        }
        else
        {
            readbytes += err ;
        }
    }
    return readbytes;
}
</code></pre>

<p>server.h:</p>

<pre><code>#include "common.h"

//If the key and the certificate are in the same file, these two can be the same
#define CERTFILE "/root/certificates/server.cert.pem"
#define KEYFILE "/root/certificates/server.key.pem"

//One of the two values below can be NULL but not both
#define CAFILE "/root/certificates/ca-chain.cert.pem"
#define CADIR NULL

SSL_CTX *ctx = NULL;
BIO *acc = NULL;

void cleanup_(void) ;

//Does the setup of the server (loading SSL libraries, loading certificates, etc)
SSL_CTX *setup_server_ctx_(void) ;

//Exchange of data with the clien
int exchange_data_(SSL *ssl) ;

//Does the whole communication once the connection is established
void communicate_(SSL *ssl) ;

//Waits for clients, establishes the connection and then proceeds to
//call communicate_()
void run_server_(void) ;
</code></pre>

<p>server.c:</p>

<pre><code>#include "server.h"
#include "logger.h"
#include &lt;sys/time.h&gt;


SSL_CTX *setup_server_ctx_(void)
{
    SSL_CTX *ctx;

    init_OpenSSL();

    //This is my function, gotta investigate it and see what should be there (maybe I got it right?)
    SEED_PRNG_();

    // This specifies that either SSL or TLS can be used
    // Later, we will "filter" out SSLv2
    ctx = SSL_CTX_new(SSL_METHOD_);

    // NULL return value indicates a failure in creation of SSL_CTX object
    if(ctx == NULL)
    {
        int_error("Setup error: The creation of a new SSL_CTX object failed.");
    }
    SSL_CTX_set_options(ctx, SSL_CTX_FLAGS_);

    // These two functions are used to load trusted CAs
    if (SSL_CTX_load_verify_locations(ctx, CAFILE, CADIR) != 1)
    {
        int_error("Setup error: Error loading CA file and/or directory");
    }
    if (SSL_CTX_set_default_verify_paths(ctx) != 1)
    {
        int_error("Setup error: Error loading default CA file and/or directory");
    }

    // This loads a certificate from a file
    if (SSL_CTX_use_certificate_chain_file(ctx, CERTFILE) != 1)
    {
            int_error("Setup error: Error loading certificate from file");
    }
    // This loads a private key (can be the same file as certificate)
    if (SSL_CTX_use_PrivateKey_file(ctx, KEYFILE, SSL_FILETYPE_PEM) != 1)
    {
            int_error("Setup error: Error loading private key from file");
    }
    if (SSL_CTX_set_cipher_list(ctx, CIPHER_LIST) != 1)
    {
        int_error("Error setting cipher list (no valid ciphers)");
    }
    // Setting the verify options for ctx context
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
    // Setting the maximum allowed depth for CA verification
    SSL_CTX_set_verify_depth(ctx, DEFAULT_DEPTH_);

    return ctx;
}

int exchange_data_(SSL *ssl)
{
    int err;
    err = write_to_SSL(ssl, "Hello, client!", strlen("Hello, client!"));

    if (err &lt;= 0)
    {
        printf("An unsuccessful write!");
    }
    else
    {
        printf("Sent %d bytes.\n", err);
    }

    // SSL_get_shutdown(ssl) &amp; SSL_RECEIVED_SHUTDOWN != 0 indicate that the shutdown notification
    // was sent from the peer (in this case, the client)
    //close(uart_fd);
    return (SSL_get_shutdown(ssl) &amp; SSL_RECEIVED_SHUTDOWN) ? 1 : 0;
}


void communicate_(SSL *ssl)
{
    long err;
    struct timeval tval_before, tval_after, tval_result;
    //accepting connection from ssl object (structure)

    if (SSL_accept(ssl) &lt;= 0)
    {
        int_error("Error accepting SSL connection");
    }
    fprintf(stderr, "SSL Connection opened\n");

    if (exchange_data_(ssl))
    {
        SSL_shutdown(ssl);
    }
    else
    {
        SSL_clear(ssl);
    }

    fprintf(stderr, "SSL Connection closed\n");
    SSL_free(ssl);
}


void run_server_(void)
{
    BIO  *client;
    SSL *ssl;

    //This call does the setup of the server context (see the function for more info)
    ctx = setup_server_ctx_();

    // Creates BIO and sets the accept port
    acc = BIO_new_accept(PORT);
    BIO_set_bind_mode(acc, BIO_BIND_REUSEADDR_IF_UNUSED);
    if (!acc)
    {
        int_error("Error creating server socket");
    }
    //The first call to BIO_do_accept() binds to the given port
    if (BIO_do_accept(acc) &lt;= 0)
    {
        int_error("Error binding server socket");
    }
    for (;;)
    {
        //The second BIO_do_accept() call listens on the acc BIO
        if (BIO_do_accept(acc) &lt;= 0)
        {
            int_error("Error accepting connection from client");
        }
        client = BIO_pop(acc);
        if (!(ssl = SSL_new(ctx)))
        {
            int_error("Error creating SSL context");
        }
        SSL_set_bio(ssl, client, client);
        communicate_(ssl);
    }


}

int main(int argc, char *argv[])
{
    run_server_();
    return 1;
}
</code></pre>

<p>Note: The code is mostly taken from O'Reilly book "Network Security with OpenSSL". 
Also, this is not the whole code I have but it is the whole code related to OpenSSL so I didn't deem the other code relevant.
There could be some mistakes in the code due to the copy/paste.</p>