tls_select.c

Go to the documentation of this file.
00001 /*
00002  * $Id: tls_select.c 4680 2008-08-12 07:26:43Z klaus_darilion $
00003  *
00004  * TLS module - select interface
00005  *
00006  * Copyright (C)  2001-2003 FhG FOKUS
00007  * Copyright (C)  2004,2005 Free Software Foundation, Inc.
00008  * Copyright (C)  2005 iptelorg GmbH
00009  * Copyright (C)  2006 enum.at
00010  *
00011  * This file is part of Kamailio, a free SIP server.
00012  *
00013  * Kamailio is free software; you can redistribute it and/or modify
00014  * it under the terms of the GNU General Public License as published by
00015  * the Free Software Foundation; either version 2 of the License, or
00016  * (at your option) any later version
00017  *
00018  * Kamailio is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License 
00024  * along with this program; if not, write to the Free Software 
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  *
00027  */
00028 
00029 #include <openssl/ssl.h>
00030 #include <openssl/x509v3.h>
00031 #include "../../globals.h"
00032 #include "../../tcp_server.h"
00033 #include "../../tcp_conn.h"
00034 #include "../../ut.h"
00035 #include "tls_select.h"
00036 #include "../../tls/tls_config.h"
00037 
00038 
00039 struct tcp_connection* get_cur_connection(struct sip_msg* msg)
00040 {
00041    struct tcp_connection* c;
00042 
00043    if (msg->rcv.proto != PROTO_TLS) {
00044       LM_ERR("transport protocol is not TLS (bug in config)\n");
00045       return 0;
00046    }
00047 
00048    c = tcpconn_get(msg->rcv.proto_reserved1, 0, 0, tcp_con_lifetime, 0);
00049    if (c && c->type != PROTO_TLS) {
00050       LM_ERR("connection found but is not TLS (bug in config)\n");
00051       tcpconn_put(c);
00052       return 0;
00053    }
00054    return c;
00055 }
00056 
00057 
00058 static inline SSL* get_ssl(struct tcp_connection* c)
00059 {
00060    if (!c || !c->extra_data) {
00061       LM_ERR("failed to extract SSL data from TLS connection\n");
00062       return 0;
00063    }
00064    return c->extra_data;
00065 }
00066 
00067 
00068 static inline int get_cert(X509** cert, struct tcp_connection** c,
00069                                     struct sip_msg* msg, int my)
00070 {
00071    SSL* ssl;
00072 
00073    *cert = 0;
00074    *c = get_cur_connection(msg);
00075    if (!(*c)) {
00076       LM_INFO("TLS connection not found\n");
00077       return -1;
00078    }
00079    ssl = get_ssl(*c);
00080    if (!ssl) goto err;
00081    *cert = my ? SSL_get_certificate(ssl) : SSL_get_peer_certificate(ssl);
00082    if (!*cert) {
00083       LM_ERR("failed to get certificate from SSL structure\n");
00084       goto err;
00085    }
00086 
00087    return 0;
00088 err:
00089    tcpconn_put(*c);
00090    return -1;
00091 }
00092 
00093 
00094 int tlsops_cipher(struct sip_msg *msg, pv_param_t *param,
00095       pv_value_t *res)
00096 {
00097    str cipher;
00098    static char buf[1024];
00099 
00100    struct tcp_connection* c;
00101    SSL* ssl;
00102 
00103    c = get_cur_connection(msg);
00104    if (!c) {
00105       LM_INFO("TLS connection not found in select_cipher\n");
00106       goto err;
00107    }
00108    ssl = get_ssl(c);
00109    if (!ssl) goto err;
00110 
00111    cipher.s = (char*)SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
00112    cipher.len = cipher.s ? strlen(cipher.s) : 0;
00113    if (cipher.len >= 1024) {
00114       LM_ERR("cipher name too long\n");
00115       goto err;
00116    }
00117    memcpy(buf, cipher.s, cipher.len);
00118    res->rs.s = buf;
00119    res->rs.len = cipher.len;
00120    res->flags = PV_VAL_STR;
00121    tcpconn_put(c);
00122 
00123    return 0;
00124 err:
00125    if (c) tcpconn_put(c);
00126    return pv_get_null(msg, param, res);
00127 }
00128 
00129 
00130 int tlsops_bits(struct sip_msg *msg, pv_param_t *param,
00131       pv_value_t *res)
00132 {
00133    str bits;
00134    int b;
00135    static char buf[1024];
00136 
00137    struct tcp_connection* c;
00138    SSL* ssl;
00139 
00140    c = get_cur_connection(msg);
00141    if (!c) {
00142       LM_INFO("TLS connection not found in select_bits\n");
00143       goto err;
00144    }
00145    ssl = get_ssl(c);
00146    if (!ssl) goto err;
00147 
00148    b = SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), 0);
00149    bits.s = int2str(b, &bits.len);
00150    if (bits.len >= 1024) {
00151       LM_ERR("bits string too long\n");
00152       goto err;
00153    }
00154    memcpy(buf, bits.s, bits.len);
00155    res->rs.s = buf;
00156    res->rs.len = bits.len;
00157    res->ri = b;
00158    res->flags = PV_VAL_STR | PV_VAL_INT;
00159    tcpconn_put(c);
00160 
00161    return 0;
00162 err:
00163    if (c) tcpconn_put(c);
00164    return pv_get_null(msg, param, res);
00165 }
00166 
00167 
00168 int tlsops_version(struct sip_msg *msg, pv_param_t *param,
00169       pv_value_t *res)
00170 {
00171    str version;
00172    static char buf[1024];
00173 
00174    struct tcp_connection* c;
00175    SSL* ssl;
00176 
00177    c = get_cur_connection(msg);
00178    if (!c) {
00179       LM_INFO("TLS connection not found in select_version\n");
00180       goto err;
00181    }
00182    ssl = get_ssl(c);
00183    if (!ssl) goto err;
00184 
00185    version.s = (char*)SSL_get_version(ssl);
00186    version.len = version.s ? strlen(version.s) : 0;
00187    if (version.len >= 1024) {
00188       LM_ERR("version string too long\n");
00189       goto err;
00190    }
00191    memcpy(buf, version.s, version.len);
00192 
00193    res->rs.s = buf;
00194    res->rs.len = version.len;
00195    res->flags = PV_VAL_STR;
00196 
00197    tcpconn_put(c);
00198 
00199    return 0;
00200 err:
00201    if (c) tcpconn_put(c);
00202    return pv_get_null(msg, param, res);
00203 }
00204 
00205 
00206 int tlsops_desc(struct sip_msg *msg, pv_param_t *param,
00207       pv_value_t *res)
00208 {
00209    static char buf[128];
00210 
00211    struct tcp_connection* c;
00212    SSL* ssl;
00213 
00214    c = get_cur_connection(msg);
00215    if (!c) {
00216       LM_INFO("TLS connection not found in select_desc\n");
00217       goto err;
00218    }
00219    ssl = get_ssl(c);
00220    if (!ssl) goto err;
00221 
00222    buf[0] = '\0';
00223    SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, 128);
00224    res->rs.s = buf;
00225    res->rs.len = strlen(buf);
00226    res->flags = PV_VAL_STR;
00227 
00228    tcpconn_put(c);
00229 
00230    return 0;
00231 err:
00232    if (c) tcpconn_put(c);
00233    return pv_get_null(msg, param, res);
00234 }
00235 
00236 
00237 int tlsops_cert_version(struct sip_msg *msg, pv_param_t *param,
00238       pv_value_t *res)
00239 {
00240    static char buf[INT2STR_MAX_LEN];
00241    X509* cert;
00242    struct tcp_connection* c;
00243    char* version;
00244    int my;
00245 
00246    if (param->pvn.u.isname.name.n & CERT_PEER) {
00247       my = 0;
00248    } else if (param->pvn.u.isname.name.n & CERT_LOCAL) {
00249       my = 1;
00250    } else {
00251       LM_CRIT("bug in call to tlsops_cert_version\n");
00252       return pv_get_null(msg, param, res);
00253    }
00254 
00255    if (get_cert(&cert, &c, msg, my) < 0) return -1;
00256    version = int2str(X509_get_version(cert), &res->rs.len);
00257    memcpy(buf, version, res->rs.len);
00258    res->rs.s = buf;
00259    res->flags = PV_VAL_STR;
00260    if (!my) X509_free(cert);
00261    tcpconn_put(c);
00262    return 0;
00263 }
00264 
00265 
00266 /*
00267  * Check whether peer certificate exists and verify the result
00268  * of certificate verification
00269  */
00270 int tlsops_check_cert(struct sip_msg *msg, pv_param_t *param,
00271       pv_value_t *res)
00272 {
00273    static str succ = str_init("1");
00274    static str fail = str_init("0");
00275 
00276    int err;
00277    struct tcp_connection* c;
00278    SSL* ssl;
00279    X509* cert = 0;
00280 
00281    switch (param->pvn.u.isname.name.n) {
00282    case CERT_VERIFIED:   err = X509_V_OK;                              break;
00283    case CERT_REVOKED:    err = X509_V_ERR_CERT_REVOKED;                break;
00284    case CERT_EXPIRED:    err = X509_V_ERR_CERT_HAS_EXPIRED;            break;
00285    case CERT_SELFSIGNED: err = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; break;
00286    default:
00287       LM_CRIT("unexpected parameter value \"%d\"\n",
00288             param->pvn.u.isname.name.n);
00289       return pv_get_null(msg, param, res);
00290    }   
00291 
00292    c = get_cur_connection(msg);
00293    if (!c) return -1;
00294 
00295    ssl = get_ssl(c);
00296    if (!ssl) goto err;
00297 
00298    if ((cert = SSL_get_peer_certificate(ssl)) && SSL_get_verify_result(ssl) == err) {
00299       res->rs.s = succ.s;
00300       res->rs.len = succ.len;
00301       res->ri   = 1;
00302    } else {
00303       res->rs.s = fail.s;
00304       res->rs.len = fail.len;
00305       res->ri   = 0;
00306    }
00307    res->flags = PV_VAL_STR | PV_VAL_INT;
00308 
00309    if (cert) X509_free(cert);
00310    tcpconn_put(c);
00311 
00312    return 0;
00313 err:
00314    if (cert) X509_free(cert);
00315    if (c) tcpconn_put(c);
00316    return pv_get_null(msg, param, res);
00317 }
00318 
00319 
00320 int tlsops_validity(struct sip_msg *msg, pv_param_t *param,
00321       pv_value_t *res)
00322 {
00323    static char buf[1024];
00324    X509* cert;
00325    struct tcp_connection* c;
00326    BUF_MEM* p;
00327    BIO* mem = 0;
00328    ASN1_TIME* date;
00329    int my = 0;
00330 
00331    if (get_cert(&cert, &c, msg, my) < 0) return -1;
00332 
00333    switch (param->pvn.u.isname.name.n) {
00334    case CERT_NOTBEFORE: date = X509_get_notBefore(cert); break;
00335    case CERT_NOTAFTER:  date = X509_get_notAfter(cert);  break;
00336    default:
00337       LM_CRIT("unexpected parameter value \"%d\"\n", param->pvn.u.isname.name.n);
00338       goto err;
00339    }
00340 
00341    mem = BIO_new(BIO_s_mem());
00342    if (!mem) {
00343       LM_ERR("failed to create memory BIO\n");
00344       goto err;
00345    }
00346 
00347    if (!ASN1_TIME_print(mem, date)) {
00348       LM_ERR("failed to print certificate date/time\n");
00349       goto err;
00350    }
00351    
00352    BIO_get_mem_ptr(mem, &p);
00353    if (p->length >= 1024) {
00354       LM_ERR("Date/time too long\n");
00355       goto err;
00356    }
00357    memcpy(buf, p->data, p->length);
00358    res->rs.s = buf;
00359    res->rs.len = p->length;
00360    res->flags = PV_VAL_STR ;
00361 
00362    BIO_free(mem);
00363    if (!my) X509_free(cert);
00364    tcpconn_put(c);
00365 
00366    return 0;
00367 err:
00368    if (mem) BIO_free(mem);
00369    if (!my) X509_free(cert);
00370    tcpconn_put(c);
00371    return pv_get_null(msg, param, res);
00372 }
00373 
00374 
00375 int tlsops_sn(struct sip_msg *msg, pv_param_t *param,
00376       pv_value_t *res)
00377 {
00378    static char buf[INT2STR_MAX_LEN];
00379    X509* cert;
00380    struct tcp_connection* c;
00381    int my, serial;
00382    char* sn;
00383 
00384    if (param->pvn.u.isname.name.n & CERT_PEER) {
00385       my = 0;
00386    } else if (param->pvn.u.isname.name.n & CERT_LOCAL) {
00387       my = 1;
00388    } else {
00389       LM_CRIT("could not determine certificate\n");
00390       return pv_get_null(msg, param, res);
00391    }
00392    
00393    if (get_cert(&cert, &c, msg, my) < 0)
00394       return pv_get_null(msg, param, res);
00395    
00396    serial = ASN1_INTEGER_get(X509_get_serialNumber(cert));
00397    sn = int2str( serial, &res->rs.len);
00398    memcpy(buf, sn, res->rs.len);
00399    res->rs.s = buf;
00400    res->ri = serial;
00401    res->flags = PV_VAL_STR | PV_VAL_INT;  
00402    
00403    if (!my) X509_free(cert);
00404    tcpconn_put(c);
00405    return 0;
00406 }
00407 
00408 int tlsops_comp(struct sip_msg *msg, pv_param_t *param,
00409       pv_value_t *res)
00410 {
00411    static char buf[1024];
00412    X509* cert;
00413    struct tcp_connection* c;
00414    X509_NAME* name;
00415    X509_NAME_ENTRY* e;
00416    ASN1_STRING* asn1;
00417    int nid = NID_commonName, index, my = 0, issuer = 0, ind_local;
00418    char* elem;
00419    str text;
00420 
00421    text.s = 0;
00422    /* copy callback value as we modify it */
00423    ind_local = param->pvn.u.isname.name.n;
00424 
00425    LM_DBG("ind_local = %x", ind_local);
00426    if (ind_local & CERT_PEER) {
00427       my = 0;
00428       ind_local = ind_local ^ CERT_PEER;
00429    } else if (ind_local & CERT_LOCAL) {
00430       my = 1;
00431       ind_local = ind_local ^ CERT_LOCAL;
00432    } else {
00433       LM_CRIT("could not determine certificate\n");
00434       return pv_get_null(msg, param, res);
00435    }
00436 
00437    if (ind_local & CERT_SUBJECT) {
00438       issuer = 0;
00439       ind_local = ind_local ^ CERT_SUBJECT;
00440    } else if (ind_local & CERT_ISSUER) {
00441       issuer = 1;
00442       ind_local = ind_local ^ CERT_ISSUER;
00443    } else {
00444       LM_CRIT("could not determine subject or issuer\n");
00445       return pv_get_null(msg, param, res);
00446    }
00447 
00448    switch(ind_local) {
00449       case COMP_CN: nid = NID_commonName;             break;
00450       case COMP_O:  nid = NID_organizationName;       break;
00451       case COMP_OU: nid = NID_organizationalUnitName; break;
00452       case COMP_C:  nid = NID_countryName;            break;
00453       case COMP_ST: nid = NID_stateOrProvinceName;    break;
00454       case COMP_L:  nid = NID_localityName;           break;
00455       default:      nid = NID_undef;
00456    }
00457 
00458    if (get_cert(&cert, &c, msg, my) < 0) return -1;
00459 
00460    name = issuer ? X509_get_issuer_name(cert) : X509_get_subject_name(cert);
00461    if (!name) {
00462       LM_ERR("cannot extract subject or issuer name from peer"
00463             " certificate\n");
00464       goto err;
00465    }
00466 
00467    if (nid == NID_undef) { /* dump the whole cert info into buf */
00468       X509_NAME_oneline(name, buf, sizeof(buf));
00469       res->rs.s = buf;
00470       res->rs.len = strlen(buf);
00471       res->flags = PV_VAL_STR;
00472    } else {
00473       index = X509_NAME_get_index_by_NID(name, nid, -1);
00474       if (index == -1) {
00475          switch(ind_local) {
00476          case COMP_CN: elem = "CommonName";              break;
00477          case COMP_O:  elem = "OrganizationName";        break;
00478          case COMP_OU: elem = "OrganizationalUnitUname"; break;
00479          case COMP_C:  elem = "CountryName";             break;
00480          case COMP_ST: elem = "StateOrProvinceName";     break;
00481          case COMP_L:  elem = "LocalityName";            break;
00482          default:      elem = "Unknown";                 break;
00483          }
00484          LM_DBG("element %s not found in "
00485             "certificate subject/issuer\n", elem);
00486          goto err;
00487       }
00488    
00489       e = X509_NAME_get_entry(name, index);
00490       asn1 = X509_NAME_ENTRY_get_data(e);
00491       text.len = ASN1_STRING_to_UTF8((unsigned char**)(void*)&text.s, asn1);
00492       if (text.len < 0 || text.len >= 1024) {
00493          LM_ERR("failed to convert ASN1 string\n");
00494          goto err;
00495       }
00496       memcpy(buf, text.s, text.len);
00497       res->rs.s = buf;
00498       res->rs.len = text.len;
00499       res->flags = PV_VAL_STR;
00500    
00501       OPENSSL_free(text.s);
00502    }
00503    if (!my) X509_free(cert);
00504    tcpconn_put(c);
00505    return 0;
00506 
00507  err:
00508    if (text.s) OPENSSL_free(text.s);
00509    if (!my) X509_free(cert);
00510    tcpconn_put(c);
00511    return pv_get_null(msg, param, res);
00512 }
00513 
00514 int tlsops_alt(struct sip_msg *msg, pv_param_t *param,
00515       pv_value_t *res)
00516 {
00517    static char buf[1024];
00518    int type = GEN_URI, my = 0, n, found = 0, ind_local;
00519    STACK_OF(GENERAL_NAME)* names = 0;
00520    GENERAL_NAME* nm;
00521    X509* cert;
00522    struct tcp_connection* c;
00523    str text;
00524    struct ip_addr ip;
00525 
00526    ind_local = param->pvn.u.isname.name.n;
00527 
00528    if (ind_local & CERT_PEER) {
00529       my = 0;
00530       ind_local = ind_local ^ CERT_PEER;
00531    } else if (ind_local & CERT_LOCAL) {
00532       my = 1;
00533       ind_local = ind_local ^ CERT_LOCAL;
00534    } else {
00535       LM_CRIT("could not determine certificate\n");
00536       return pv_get_null(msg, param, res);
00537    }
00538 
00539    switch(ind_local) {
00540       case COMP_E:    type = GEN_EMAIL; break;
00541       case COMP_HOST: type = GEN_DNS;   break;
00542       case COMP_URI:  type = GEN_URI;   break;
00543       case COMP_IP:   type = GEN_IPADD; break;
00544       default:
00545          LM_CRIT("ind_local=%d\n", ind_local);
00546          return pv_get_null(msg, param, res);
00547    }
00548 
00549    if (get_cert(&cert, &c, msg, my) < 0) return -1;
00550 
00551    names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
00552    if (!names) {
00553       LM_ERR("cannot get certificate alternative subject\n");
00554       goto err;
00555 
00556    }
00557 
00558    for (n = 0; n < sk_GENERAL_NAME_num(names); n++) {
00559       nm = sk_GENERAL_NAME_value(names, n);
00560       if (nm->type != type) continue;
00561       switch(type) {
00562       case GEN_EMAIL:
00563       case GEN_DNS:
00564       case GEN_URI:
00565          text.s = (char*)nm->d.ia5->data;
00566          text.len = nm->d.ia5->length;
00567          if (text.len >= 1024) {
00568             LM_ERR("alternative subject text too long\n");
00569             goto err;
00570          }
00571          memcpy(buf, text.s, text.len);
00572          res->rs.s = buf;
00573          res->rs.len = text.len;
00574          res->flags = PV_VAL_STR;
00575          found = 1;
00576          break;
00577 
00578       case GEN_IPADD:
00579          ip.len = nm->d.iPAddress->length;
00580          ip.af = (ip.len == 16) ? AF_INET6 : AF_INET;
00581          memcpy(ip.u.addr, nm->d.iPAddress->data, ip.len);
00582          text.s = ip_addr2a(&ip);
00583          text.len = strlen(text.s);
00584          memcpy(buf, text.s, text.len);
00585          res->rs.s = buf;
00586          res->rs.len = text.len;
00587          res->flags = PV_VAL_STR;
00588          found = 1;
00589          break;
00590       }
00591       break;
00592    }
00593    if (!found) goto err;
00594 
00595    if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
00596    if (!my) X509_free(cert);
00597    tcpconn_put(c);
00598    return 0;
00599  err:
00600    if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
00601    if (!my) X509_free(cert);
00602    tcpconn_put(c);
00603    return pv_get_null(msg, param, res);
00604 }
00605 
00606 
00607 
00608 #ifdef OPENSSL_NO_TLSEXT
00609 int tlsops_tlsext(struct sip_msg *msg, pv_param_t *param,
00610       pv_value_t *res)
00611 {
00612    LM_ERR("TLS extension 'server name' pseudo variable is not available! "
00613       "please install openssl with TLS extension support and recompile "
00614       "openser\n");
00615    return pv_get_null(msg, param, res);
00616 }
00617 #else
00618 int tlsops_tlsext(struct sip_msg *msg, pv_param_t *param,
00619       pv_value_t *res)
00620 {
00621    static char buf[1024];
00622    struct tcp_connection* c;
00623    SSL* ssl;
00624 
00625    c = get_cur_connection(msg);
00626    if (!c) {
00627       LM_INFO("TLS connection not found in select_desc\n");
00628       goto err;
00629    }
00630    ssl = get_ssl(c);
00631    if (!ssl) goto err;
00632    buf[0] = '\0';
00633 
00634    switch (param->pvn.u.isname.name.n) {
00635    case TLSEXT_SNI:
00636       {  const char *server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
00637          if (server_name)  {
00638             LM_DBG("received server_name (TLS extension): '%s'\n",server_name);
00639          } else {
00640             LM_DBG("SSL_get_servername returned NULL\n");
00641             return pv_get_null(msg, param, res);
00642          }
00643 
00644          /* copy server_name into PV buffer. If the buffer is too small copy only the
00645           * last bytes as these are the more important ones and prefix with '+' */
00646          if (strlen(server_name) > sizeof(buf)) {
00647             LM_ERR("server_name to big for buffer\n");
00648             buf[0] = '+';
00649             memcpy(buf+1, server_name+1+strlen(server_name)-sizeof(buf), sizeof(buf)-1);
00650             res->rs.len = sizeof(buf);
00651          } else {
00652             memcpy(buf, server_name, strlen(server_name));
00653             res->rs.len = strlen(server_name);
00654          }
00655          res->rs.s = buf;
00656          res->flags = PV_VAL_STR;
00657       }
00658       break;
00659 
00660    default:
00661       LM_CRIT("unexpected parameter value \"%d\"\n",
00662          param->pvn.u.isname.name.n);
00663       tcpconn_put(c);
00664       return pv_get_null(msg, param, res);
00665    }
00666 
00667    tcpconn_put(c);
00668    return 0;
00669 err:
00670    if (c) tcpconn_put(c);
00671    return pv_get_null(msg, param, res);
00672 }
00673 #endif

Generated on Thu May 24 20:00:33 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6