2016-08-25 105 views
0

我在Dragino Yun上運行openwrt。我的願望是在Dragino上運行一個openssl服務器,用於傳輸一些(不是很多)數據。但是,啓動服務器並加載證書後,對BIO_do_accept()的調用返回值< = 0,表示綁定失敗。我試圖綁定的端口是5354,但我甚至嘗試了8081,8080,443。OpenSSL openwrt失敗套接字綁定

的錯誤信息,我從ERR_print_errors_fp得到的是:

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

任何人可以解釋爲什麼我的程序無法綁定?我在Ubuntu上測試過 - 這就是爲什麼我沒有發佈任何代碼 - (我遇到的問題是交叉編譯版本),OpenSSL版本爲OpenSSL 1.0.1f 6 Jan 2014,在Dragino上,OpenSSL版本爲:OpenSSL 1.0.1h 5 Jun 2014。 另外,Dragino版本(從橫幅)是Dragino-v2 common-2.0.5

我使用s_server嘗試和結果如下:

[email protected]:~/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 

其中,當使用的s_client.First,產生了一些通信,因此,套接字綁定是確定。

那麼,什麼是問題,我該如何正確工作呢? 我試着用谷歌搜索錯誤信息,但無濟於事。

另外,我改變了iptables在INPUT,FORWARD和OUTPUT鏈上有ACCEPT默認策略。

編輯:添加代碼。

COMMON.H:

#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) ; 

common.c中:

#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 >= 0 && writtenbytes < length) 
    { 
     err = SSL_write(ssl, msg + writtenbytes, length - writtenbytes); 
     if(err < 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 > 0 && readbytes < length) 
    { 
     err = SSL_read(ssl, msg + readbytes, length - readbytes); 

     if(err < 0) 
     { 
      return err; 
     } 
     else 
     { 
      readbytes += err ; 
     } 
    } 
    return readbytes; 
} 

server.h:

#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) ; 

server.c:

#include "server.h" 
#include "logger.h" 
#include <sys/time.h> 


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 <= 0) 
    { 
     printf("An unsuccessful write!"); 
    } 
    else 
    { 
     printf("Sent %d bytes.\n", err); 
    } 

    // SSL_get_shutdown(ssl) & 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) & 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) <= 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) <= 0) 
    { 
     int_error("Error binding server socket"); 
    } 
    for (;;) 
    { 
     //The second BIO_do_accept() call listens on the acc BIO 
     if (BIO_do_accept(acc) <= 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; 
} 

注意:代碼主要來自O'Reilly的書籍「使用OpenSSL的網絡安全」。另外,這不是我所有的代碼,但它是與OpenSSL相關的整個代碼,所以我不認爲其他代碼相關。 由於複製/粘貼,代碼可能存在一些錯誤。

+0

*「任何人可以解釋爲什麼是我的程序無法綁定?」 * - 不,因爲你沒有提供相關的源代碼。在這一點上,你應該***編輯你的問題並添加相關的源代碼。包含相關參數,如連接記錄和服務器URLS。 – jww

+0

我實際測試了Ubuntu上的代碼,就像我寫下的那樣。但是,好吧,我會在編輯中發佈一些代碼。 – NMilev

+0

我編輯了原帖。 @jww – NMilev

回答

0

聯繫OpenSSL團隊後,他們得出結論:OpenSSL調用BIO_do_accept()的問題在致電socket()。奇怪的是,當我編寫我自己的簡單服務器應用程序時,調用socket()似乎工作正常。所以,他們提出了一種解決方法:我現在使用的是系統調用,而不是使用BIO調用。這降低了代碼的可移植性,但對我而言,這並不重要。

run_server_()函數現在看起來是這樣的:

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

    int  listenfd, connfd; 
    socklen_t clilen; 
    struct sockaddr_in cliaddr, servaddr; 

    ctx = setup_server_ctx_(); 

    listenfd = socket (AF_INET, SOCK_STREAM, PROTOCOL); 
    if(listenfd < 0) 
    { 
     printf("serv_socket unsuccessful\n"); 
     exit(EXIT_FAILURE); 
    } 
    printf("Created socket!\n"); 
    memset(&servaddr, 0, sizeof(servaddr)); 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_addr.s_addr = htonl (INADDR_ANY); 
    servaddr.sin_port = htons (atoi(PORT)); 

    if(bind(listenfd, (const struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) 
    { 
     printf("bind() error\n"); 
     exit(EXIT_FAILURE); 
    } 
    printf("Binded port/socket!\n"); 

    if(listen(listenfd, LISTENQ) < 0) 
    { 
     printf("listen() error\n"); 
     exit(EXIT_FAILURE); 
    } 
    printf("Listening!\n"); 

    for(;;) 
    { 
     clilen = sizeof(cliaddr); 
     connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen); 
     if(connfd < 0) 
     { 
      printf("accept() error\n"); 
     } 
     printf("Accepted!\n"); 
     client = BIO_new(BIO_s_socket()); 

    if (client == NULL) 
     { 
      printf("error creating BIO\n"); 
    } 
    BIO_set_fd(client, connfd, BIO_NOCLOSE); 
     if (!(ssl = SSL_new(ctx))) 
     { 
      server_error_("Error creating SSL context"); 
     } 
     SSL_set_bio(ssl, client, client); 
     communicate_(ssl); 

     close(connfd); 
    } 
}