ssl_accept () возвращает SSL_ERROR_SYSCALL в c - PullRequest
0 голосов
/ 18 января 2020

Я написал C программу, которая защищает http traffi c с использованием библиотеки openssl:

#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/crypto.h>
#include <openssl/bn.h>


#include <string.h>

#include <sys/socket.h>
#include <netinet/in.h>

#define IP_ADDR INADDR_ANY
#define PORT 8082

int password_cb(char *buf, int size, int rwflag, void *password);

EVP_PKEY *generatePrivateKey();
X509 *generateCertificate(EVP_PKEY *pkey);

/**
* Example SSL server that accepts a client and echos back anything it receives.
* Test using `curl -I https://10.10.10.101:443 --insecure --sslv3`
*/
int main(int arc, char **argv)
{
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        printf("opening socket\n");

    return -4;
    }

    struct sockaddr_in s_addr;
    bzero((char *)&s_addr, sizeof(s_addr));
    s_addr.sin_family = AF_INET;
    s_addr.sin_addr.s_addr = IP_ADDR;
    s_addr.sin_port = htons(PORT);

    if (bind(fd, (struct sockaddr*)&s_addr, sizeof(s_addr)) < 0) {
        printf("binding\n");
        return -5;
    }

    listen(fd, 2);

    int cfd;    
    while (cfd = accept(fd, 0, 0))
    {
        SSL_load_error_strings();
        ERR_load_crypto_strings();

        OpenSSL_add_all_algorithms();
        SSL_library_init();

        SSL_CTX *ctx = SSL_CTX_new(SSLv3_server_method());
        //SSL_CTX *ctx = SSL_CTX_new(TLS_server_method());
        if (ctx == NULL) {


            printf("errored; unable to load context.\n");
            ERR_print_errors_fp(stderr);
            return -3;
    }

    EVP_PKEY *pkey = generatePrivateKey();
    X509 *x509 = generateCertificate(pkey);

    SSL_CTX_use_certificate(ctx, x509);
    SSL_CTX_set_default_passwd_cb(ctx, password_cb);
    SSL_CTX_use_PrivateKey(ctx, pkey);

    RSA *rsa=RSA_generate_key(512, RSA_F4, NULL, NULL); 
    SSL_CTX_set_tmp_rsa(ctx, rsa); 
    RSA_free(rsa);

    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);

    SSL *ssl = SSL_new(ctx);

    BIO *accept_bio = BIO_new_socket(cfd, BIO_CLOSE);
    SSL_set_bio(ssl, accept_bio, accept_bio);


    int n = SSL_accept(ssl);

    switch (SSL_get_error(ssl, n))
        { 
        case SSL_ERROR_NONE: 
             printf("SSL_ERROR_NONE\n");
            break;
        case SSL_ERROR_ZERO_RETURN: 
             printf("SSL_ERROR_ZERO_RETURN\n");
             goto end; 

        case SSL_ERROR_WANT_READ: 
             printf("SSL_ERROR_WANT_READ\n");
             goto end;


        case SSL_ERROR_WANT_WRITE: 
             printf("SSL_ERROR_WANT_WRITE\n");
             goto end;


        case SSL_ERROR_WANT_CONNECT:
                printf("SSL_ERROR_WANT_CONNECT\n");
                goto end;


        case  SSL_ERROR_WANT_ACCEPT:
                printf("SSL_ERROR_WANT_ACCEPT\n");
                goto end;



        case  SSL_ERROR_SSL:
                printf("SSL_ERROR_SSL\n");
                goto end;     

       case  SSL_ERROR_SYSCALL:
                printf("SSL_ERROR_SYSCALL\n");
                goto end;  

        default: 
            printf("SSL accept problem\n");

            goto end;
        }*/

    //printf("ssl accept return value : %d", n);
    //ERR_print_errors_fp(stderr); 





    BIO *bio = BIO_pop(accept_bio);

    char buf[1024];


    while (1)
    {
        // first read data

        int r = SSL_read(ssl, buf, 1024); 
    FILE *file1 = fopen("logfile", "a");
    fprintf(file1, "len of read data : %d\n", r);
    fprintf(file1, "content of read data : %s\n", buf);
    fclose(file1);


        int ssl_error = SSL_get_error(ssl, r);
        fprintf(file1, " SSL_get_error : %d\n", ssl_error);

        printf ("\nsize of read data : %d\n", r);

        printf ("actual data : %s\n", buf);

        switch (SSL_get_error(ssl, r))
        { 
        case SSL_ERROR_NONE: 
            break;
        case SSL_ERROR_ZERO_RETURN: 
            goto end; 
        default: 
            printf("SSL read problem");
            goto end;
        }

        int len = r;

        // now keep writing until we've written everything
        int offset = 0;
        while (len)
        {
            r = SSL_write(ssl, buf + offset, len); 
            switch (SSL_get_error(ssl, r))
            { 
            case SSL_ERROR_NONE: 
                len -= r;
                offset += r; 
                break;
            default:
                printf("SSL write problem");
                goto end;
            }
        }
    }

end:

    SSL_shutdown(ssl);

    BIO_free_all(bio);
    BIO_free_all(accept_bio);
    }

    return 0;
}

int password_cb(char *buf, int size, int rwflag, void *password)
{
        strncpy(buf, (char *)(password), size);
        buf[size - 1] = '\0';
        return strlen(buf);
}

EVP_PKEY *generatePrivateKey()
{
        EVP_PKEY *pkey = NULL;
        EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
     EVP_PKEY_keygen_init(pctx);
        EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, 2048);
        EVP_PKEY_keygen(pctx, &pkey);
     return pkey;
}

X509 *generateCertificate(EVP_PKEY *pkey)
{
        X509 *x509 = X509_new();
     X509_set_version(x509, 2);
     ASN1_INTEGER_set(X509_get_serialNumber(x509), 0);
     X509_gmtime_adj(X509_get_notBefore(x509), 0);
     X509_gmtime_adj(X509_get_notAfter(x509), (long)60*60*24*365);
        X509_set_pubkey(x509, pkey);

     X509_NAME *name = X509_get_subject_name(x509);
     X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (const unsigned char*)"US", -1, -1, 0);
        X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (const unsigned char*)"YourCN", -1, -1, 0);
        X509_set_issuer_name(x509, name);
        X509_sign(x509, pkey, EVP_md5());
     return x509;
}

Я использую эту команду для подключения и тестирования программы:

curl -I https://10.10.10.101:443 --insecure --sslv3

Проблема в том, что строка int n = ssl_accept (ssl) возвращает -1 значение. Когда я использую get_ssl_error () , чтобы точно определить проблему, он показывает ssl_error_syscall .

, также я использую printf ("error:% s \ n" , strerror (errno)) после ssl_accept (), и я получаю это в качестве вывода:

bad file descriptor

Я искал эти сообщения. в ссылке https://linux.die.net/man/3/ssl_accept говорится, что значение -1, возвращаемое ssl_accept , равно:

Рукопожатие TLS / SSL не было успешным, потому что фатальное ошибка произошла либо на уровне протокола, либо произошел сбой соединения. Выключение не было чистым. Также может возникнуть действие, необходимо продолжить операцию для неблокирования B IOs. Вызовите SSL_get_error () с возвращаемым значением ret, чтобы выяснить причину.

также по ссылке https://man.openbsd.org/SSL_get_error.3, где говорится о ssl_error_syscall :

Произошла ошибка ввода-вывода. Очередь ошибок OpenSSL может содержать больше информации об ошибке. Если очередь ошибок пуста (т. Е. ERR_get_error () возвращает 0), ret можно использовать, чтобы узнать больше об ошибке: если ret == 0, наблюдался EOF, который нарушает протокол. Если ret == -1, базовый BIO сообщил об ошибке ввода / вывода (для ввода / вывода с сокетом в Unix системах обратитесь к errno для получения подробной информации).

Я новичок в C программирование и сокеты, и я не понял что-то полезное из приведенных выше ссылок. (например, что такое фатальная ошибка или чистое отключение) кто-нибудь может объяснить их простым способом или дать мне руководство, чтобы понять, что происходит? это связано с сетью или кодом?

...