Changeset 858 for pjproject/trunk


Ignore:
Timestamp:
Dec 24, 2006 4:34:50 AM (18 years ago)
Author:
bennylp
Message:

More TLS fixes (ticket #3), it should work now in blocking mode

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip/sip_transport_tls_ossl.c

    r852 r858  
    2626#include <pj/os.h> 
    2727#include <pj/pool.h> 
     28#include <pj/sock_select.h> 
    2829#include <pj/string.h> 
     30#include <pj/compat/socket.h> 
    2931 
    3032 
     
    6163/** 
    6264 * @hideinitializer 
     65 * Error creating SSL context. 
     66 */ 
     67#define PJSIP_TLS_ECTX          PJ_EUNKNOWN 
     68/** 
     69 * @hideinitializer 
    6370 * Unable to list SSL CA list. 
    6471 */ 
     
    104111    pj_sock_t        sock; 
    105112    SSL             *ssl; 
    106     BIO             *bio; 
    107113 
    108114    pjsip_rx_data    rdata; 
     
    146152static int tls_init_count; 
    147153 
    148 /* ssl_perror() */ 
    149 #if 0 
    150 #define ssl_perror(level,obj,title)     \ 
    151 { \ 
    152     unsigned long ssl_err = ERR_get_error(); \ 
    153     char errmsg[200]; \ 
    154     ERR_error_string_n(ssl_err, errmsg, sizeof(errmsg)); \ 
    155     PJ_LOG(level,(obj, "%s: %s", title, errmsg)); \ 
    156 } 
    157 #elif 1 
    158 struct err_data 
    159 { 
    160     int lvl; 
    161     const char *snd; 
    162     const char *ttl; 
    163 }; 
    164  
    165 static int ssl_print_err_count; 
    166 static int ssl_print_err_cb(const char *str, size_t len, void *u) 
    167 { 
    168     struct err_data *e = (struct err_data *)u; 
    169     switch (e->lvl) { 
    170     case 1: 
    171         PJ_LOG(1,(e->snd, "%s: %.*s", e->ttl, len-1, str)); 
    172         break; 
    173     case 2: 
    174         PJ_LOG(2,(e->snd, "%s: %.*s", e->ttl, len-1, str)); 
    175         break; 
    176     case 3: 
    177         PJ_LOG(3,(e->snd, "%s: %.*s", e->ttl, len-1, str)); 
    178         break; 
    179     default: 
    180         PJ_LOG(4,(e->snd, "%s: %.*s", e->ttl, len-1, str)); 
    181         break; 
    182     } 
    183     ++ssl_print_err_count; 
    184     return len; 
    185 } 
    186  
    187 static void ssl_perror(int level, const char *sender, const char *title) 
    188 { 
    189     struct err_data e; 
    190     int count = ssl_print_err_count; 
    191     e.lvl = level; e.snd = sender; e.ttl = title; 
    192     ERR_print_errors_cb(&ssl_print_err_cb, &e); 
    193  
    194     if (count==ssl_print_err_count) 
    195         ssl_print_err_cb(" ", 1, &e); 
    196 } 
    197 #else 
    198 static void ssl_perror(int level, const char *sender, const char *title) 
    199 { 
    200     static BIO *bio_err; 
    201  
    202     if (!bio_err) { 
    203         bio_err = BIO_new_fp(stderr,BIO_NOCLOSE); 
    204     } 
    205     ERR_print_errors(bio_err); 
    206 } 
    207  
    208 #endif 
     154/* ssl_report_error() */ 
     155static void ssl_report_error(int level, const char *sender,  
     156                             const char *format, ...) 
     157{ 
     158    va_list arg; 
     159    unsigned long ssl_err; 
     160 
     161    va_start(arg, format); 
     162    ssl_err = ERR_get_error(); 
     163 
     164    if (ssl_err == 0) { 
     165        pj_log(sender, level, format, arg); 
     166    } else { 
     167        char err_format[512]; 
     168        int len; 
     169 
     170        len = pj_ansi_snprintf(err_format, sizeof(err_format), 
     171                               "%s: ", format); 
     172        ERR_error_string(ssl_err, err_format+len); 
     173         
     174        pj_log(sender, level, err_format, arg); 
     175    } 
     176 
     177    va_end(arg); 
     178} 
    209179 
    210180 
     
    255225    SSL_CTX *ctx; 
    256226         
     227    *p_ctx = NULL; 
     228 
    257229    /* Create SSL context*/ 
    258230    meth = SSLv23_method(); 
    259231    ctx = SSL_CTX_new(meth); 
     232    if (ctx == NULL) 
     233        return PJSIP_TLS_ECTX; 
     234 
     235    /* Load the CAs we trust*/ 
     236    if (ca_list_file && *ca_list_file) { 
     237        if(!(SSL_CTX_load_verify_locations(ctx, ca_list_file, 0))) { 
     238            ssl_report_error(2, lis->base.obj_name,  
     239                             "Error loading/verifying CA list file '%s'", 
     240                             ca_list_file); 
     241            SSL_CTX_free(ctx); 
     242            return PJSIP_TLS_ECALIST; 
     243        } 
     244    } 
     245 
    260246     
    261247    /* Load our keys and certificates */ 
    262     if(!(SSL_CTX_use_certificate_chain_file(ctx, keyfile))) { 
    263         ssl_perror(2, lis->base.obj_name,  
    264                    "Error loading keys and certificate file"); 
    265         SSL_CTX_free(ctx); 
    266         return PJSIP_TLS_EKEYFILE; 
    267     } 
    268  
    269     /* Set password callback */ 
    270     SSL_CTX_set_default_passwd_cb(ctx, password_cb); 
    271     SSL_CTX_set_default_passwd_cb_userdata(ctx, lis); 
    272  
    273     if(!(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))) { 
    274         ssl_perror(2, lis->base.obj_name, "Error loading private key file"); 
    275         SSL_CTX_free(ctx); 
    276         return PJSIP_TLS_EKEYFILE; 
    277     } 
    278      
    279     /* Load the CAs we trust*/ 
    280     if(!(SSL_CTX_load_verify_locations(ctx, ca_list_file, 0))) { 
    281         ssl_perror(2, lis->base.obj_name,  
    282                    "Error loading/verifying CA list file"); 
    283         SSL_CTX_free(ctx); 
    284         return PJSIP_TLS_ECALIST; 
     248    if (keyfile && *keyfile) { 
     249        if(!(SSL_CTX_use_certificate_chain_file(ctx, keyfile))) { 
     250            ssl_report_error(2, lis->base.obj_name,  
     251                             "Error loading keys and certificate file '%s'", 
     252                             keyfile); 
     253            SSL_CTX_free(ctx); 
     254            return PJSIP_TLS_EKEYFILE; 
     255        } 
     256 
     257        /* Set password callback */ 
     258        SSL_CTX_set_default_passwd_cb(ctx, password_cb); 
     259        SSL_CTX_set_default_passwd_cb_userdata(ctx, lis); 
     260 
     261        if(!(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM))) { 
     262            ssl_report_error(2, lis->base.obj_name,  
     263                             "Error loading private key file '%s'", 
     264                             keyfile); 
     265            SSL_CTX_free(ctx); 
     266            return PJSIP_TLS_EKEYFILE; 
     267        } 
    285268    } 
    286269 
     
    498481 
    499482    while (!tls_tp->quitting) { 
     483        pj_fd_set_t rd_set; 
     484        pj_time_val timeout; 
    500485        int len; 
    501486        pj_size_t size_eaten; 
     487 
     488        PJ_FD_ZERO(&rd_set); 
     489        PJ_FD_SET(tls_tp->sock, &rd_set); 
     490 
     491        timeout.sec = 1; 
     492        timeout.msec = 0; 
     493 
     494        len = pj_sock_select(tls_tp->sock, &rd_set, NULL, NULL, &timeout); 
     495        if (len < 1) 
     496            continue; 
    502497 
    503498        /* Start blocking read to SSL socket */ 
     
    535530        case SSL_ERROR_ZERO_RETURN: 
    536531            PJ_LOG(4,(tls_tp->base.obj_name, "SSL transport shutdodwn by remote")); 
    537             pjsip_transport_shutdown(&tls_tp->base); 
     532            if (!tls_tp->quitting) 
     533                pjsip_transport_shutdown(&tls_tp->base); 
    538534            goto done; 
    539535 
    540536        case SSL_ERROR_SYSCALL: 
    541537            PJ_LOG(2,(tls_tp->base.obj_name, "SSL Error: Premature close")); 
    542             pjsip_transport_shutdown(&tls_tp->base); 
     538            if (!tls_tp->quitting) 
     539                pjsip_transport_shutdown(&tls_tp->base); 
    543540            goto done; 
    544541 
    545542        default: 
    546543            PJ_LOG(2,(tls_tp->base.obj_name, "SSL read problem")); 
    547             pjsip_transport_shutdown(&tls_tp->base); 
     544            if (!tls_tp->quitting) 
     545                pjsip_transport_shutdown(&tls_tp->base); 
    548546            goto done; 
    549547        } 
    550  
    551548    } 
    552549 
    553550done: 
    554551    return 0; 
     552} 
     553 
     554 
     555PJ_DECL(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp); 
     556 
     557/* 
     558 * Perform SSL_connect upon completion of socket connect() 
     559 */ 
     560static pj_status_t perform_ssl_connect(SSL *ssl, pj_sock_t sock) 
     561{ 
     562    int status; 
     563 
     564    if (SSL_is_init_finished (ssl)) 
     565        return PJ_SUCCESS; 
     566 
     567    SSL_set_fd(ssl, (int)sock); 
     568 
     569    if (!SSL_in_connect_init (ssl)) 
     570        SSL_set_connect_state (ssl); 
     571 
     572    do { 
     573        /* These handle sets are used to set up for whatever SSL_connect 
     574         * says it wants next. They're reset on each pass around the loop. 
     575         */ 
     576        pj_fd_set_t rd_set; 
     577        pj_fd_set_t wr_set; 
     578         
     579        PJ_FD_ZERO(&rd_set); 
     580        PJ_FD_ZERO(&wr_set); 
     581 
     582        status = SSL_connect (ssl); 
     583        switch (SSL_get_error (ssl, status)) { 
     584        case SSL_ERROR_NONE: 
     585            /* Success */ 
     586            status = 0; 
     587            break; 
     588 
     589        case SSL_ERROR_WANT_WRITE: 
     590            /* Wait for more activity */ 
     591            PJ_FD_SET(sock, &wr_set); 
     592            status = 1; 
     593            break; 
     594             
     595        case SSL_ERROR_WANT_READ: 
     596            /* Wait for more activity */ 
     597            PJ_FD_SET(sock, &rd_set); 
     598            status = 1; 
     599            break; 
     600             
     601        case SSL_ERROR_ZERO_RETURN: 
     602            /* The peer has notified us that it is shutting down via 
     603             * the SSL "close_notify" message so we need to 
     604             * shutdown, too. 
     605             */ 
     606            PJ_LOG(4,(THIS_FILE, "SSL connect() failed, remote has" 
     607                                 "shutdown connection.")); 
     608            status = -1; 
     609            break; 
     610             
     611        case SSL_ERROR_SYSCALL: 
     612            /* On some platforms (e.g. MS Windows) OpenSSL does not 
     613             * store the last error in errno so explicitly do so. 
     614             * 
     615             * Explicitly check for EWOULDBLOCK since it doesn't get 
     616             * converted to an SSL_ERROR_WANT_{READ,WRITE} on some 
     617             * platforms. If SSL_connect failed outright, though, don't 
     618             * bother checking more. This can happen if the socket gets 
     619             * closed during the handshake. 
     620             */ 
     621            if (pj_get_netos_error() == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK) && 
     622                status == -1) 
     623            { 
     624                /* Although the SSL_ERROR_WANT_READ/WRITE isn't getting 
     625                 * set correctly, the read/write state should be valid. 
     626                 * Use that to decide what to do. 
     627                 */ 
     628                status = 1;               /* Wait for more activity */ 
     629                if (SSL_want_write (ssl)) 
     630                    PJ_FD_SET(sock, &wr_set); 
     631                else if (SSL_want_read (ssl)) 
     632                    PJ_FD_SET(sock, &rd_set); 
     633                else 
     634                    status = -1;        /* Doesn't want anything - bail out */ 
     635            } 
     636            else { 
     637                status = -1; 
     638            } 
     639            break; 
     640             
     641        default: 
     642            ssl_report_error(4, THIS_FILE, "SSL_connect() error"); 
     643            status = -1; 
     644            break; 
     645        } 
     646         
     647        if (status == 1) { 
     648            /* Must have at least one handle to wait for at this point. */ 
     649            pj_assert(PJ_FD_COUNT(&rd_set) == 1 ||  
     650                      PJ_FD_COUNT(&wr_set) == 1); 
     651             
     652            /* Block indefinitely if timeout pointer is zero. */ 
     653            status = pj_sock_select(FD_SETSIZE, &rd_set, &wr_set, 
     654                                    NULL, NULL); 
     655                     
     656            /* 0 is timeout, so we're done. 
     657             * -1 is error, so we're done. 
     658             * Could be both handles set (same handle in both masks) so set to 1. 
     659             */ 
     660            if (status >= 1) 
     661                status = 1; 
     662            else                 /* Timeout or socket failure */ 
     663                status = -1; 
     664        } 
     665         
     666    } while (status == 1 && !SSL_is_init_finished (ssl)); 
     667         
     668    return (status == -1 ? PJSIP_TLS_ECONNECT : PJ_SUCCESS); 
    555669} 
    556670 
     
    658772        /* Create SSL object and BIO */ 
    659773        tls_tp->ssl = SSL_new(lis->ctx); 
    660         tls_tp->bio = BIO_new_socket(sock, BIO_NOCLOSE); 
    661         SSL_set_bio(tls_tp->ssl, tls_tp->bio, tls_tp->bio); 
     774        SSL_set_verify (tls_tp->ssl, 0, 0); 
    662775 
    663776        /* Connect SSL */ 
    664         if (SSL_connect(tls_tp->ssl) <= 0) { 
    665             ssl_perror(4, tls_tp->base.obj_name, "SSL_connect() error"); 
    666             status = PJSIP_TLS_ECONNECT; 
     777        status = perform_ssl_connect(tls_tp->ssl, sock); 
     778        if (status != PJ_SUCCESS) 
    667779            goto on_error; 
    668         } 
    669780 
    670781        /* TODO: check server cert. */ 
     
    840951{ 
    841952    struct tls_transport *tls_tp = (struct tls_transport*) transport; 
     953    int bytes_sent; 
    842954 
    843955    /* This is a connection oriented protocol, so rem_addr is not used */ 
     
    845957    PJ_UNUSED_ARG(addr_len); 
    846958 
    847     /* Write to TLS */ 
    848     if (BIO_write(tls_tp->bio, tdata->buf.start ,  
    849                   tdata->buf.cur - tdata->buf.start) <= 0) 
    850     { 
    851         if(! BIO_should_retry(tls_tp->bio)) { 
    852             ssl_perror(4, transport->obj_name, "SSL send error"); 
    853             return PJSIP_TLS_ESEND; 
    854         } 
    855  
    856         /* Do something to handle the retry */ 
    857     } 
    858  
    859959    /* Data written immediately, no need to call callback */ 
    860960    PJ_UNUSED_ARG(callback); 
    861961    PJ_UNUSED_ARG(token); 
    862962 
    863     return PJ_SUCCESS; 
     963    /* Write to TLS */ 
     964    bytes_sent = SSL_write (tls_tp->ssl, tdata->buf.start, 
     965                            tdata->buf.cur - tdata->buf.start); 
     966     
     967    switch (SSL_get_error (tls_tp->ssl, bytes_sent)) { 
     968    case SSL_ERROR_NONE: 
     969        pj_assert(bytes_sent == tdata->buf.cur - tdata->buf.start); 
     970        return PJ_SUCCESS; 
     971         
     972    case SSL_ERROR_WANT_READ: 
     973    case SSL_ERROR_WANT_WRITE: 
     974        return PJ_RETURN_OS_ERROR(OSERR_EWOULDBLOCK); 
     975         
     976    case SSL_ERROR_ZERO_RETURN: 
     977        /* The peer has notified us that it is shutting down via the SSL 
     978         * "close_notify" message so we need to shutdown, too. 
     979         */ 
     980        pj_assert(bytes_sent == tdata->buf.cur - tdata->buf.start); 
     981        SSL_shutdown (tls_tp->ssl); 
     982        pjsip_transport_shutdown(transport); 
     983        return PJ_SUCCESS; 
     984         
     985    case SSL_ERROR_SYSCALL: 
     986        if (bytes_sent == 0) { 
     987            /* An EOF occured but the SSL "close_notify" message was not 
     988             * sent.  This is a protocol error, but we ignore it. 
     989             */ 
     990            pjsip_transport_shutdown(transport); 
     991            return 0; 
     992        } 
     993        return pj_get_netos_error(); 
     994         
     995    default: 
     996        /* Reset errno to prevent previous values (e.g. EWOULDBLOCK) 
     997         * from being associated with fatal SSL errors. 
     998         */ 
     999        pj_set_netos_error(0); 
     1000        ssl_report_error(4, transport->obj_name, "SSL_write error"); 
     1001        return PJSIP_TLS_ESEND; 
     1002    } 
    8641003} 
    8651004 
     
    9061045        SSL_free(tls_tp->ssl); 
    9071046        tls_tp->ssl = NULL; 
    908         tls_tp->bio = NULL; 
    9091047        tls_tp->sock = PJ_INVALID_SOCKET; 
    9101048 
Note: See TracChangeset for help on using the changeset viewer.