📄 tls_select.c
字号:
/* * $Id: tls_select.c,v 1.1 2006/05/22 15:12:23 bogdan_iancu Exp $ * * TLS module - select interface * * Copyright (C) 2001-2003 FhG FOKUS * Copyright (C) 2004,2005 Free Software Foundation, Inc. * Copyright (C) 2006 enum.at * * This file is part of openser, a free SIP server. * * openser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * openser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <openssl/ssl.h>#include <openssl/x509v3.h>#include "../../globals.h"#include "../../tcp_server.h"#include "../../tcp_conn.h"#include "../../ut.h"#include "tls_select.h"struct tcp_connection* get_cur_connection(struct sip_msg* msg){ struct tcp_connection* c; if (msg->rcv.proto != PROTO_TLS) { LOG(L_ERR,"ERROR:tlsops:get_cur_connection: transport protocol is not " "TLS (bug in config)\n"); return 0; } c = tcpconn_get(msg->rcv.proto_reserved1, 0, 0, tcp_con_lifetime); if (c && c->type != PROTO_TLS) { LOG(L_ERR,"ERROR:tlsops:get_cur_connection: connection found but is " "not TLS (bug in config)\n"); tcpconn_put(c); return 0; } return c;}static inline SSL* get_ssl(struct tcp_connection* c){ if (!c || !c->extra_data) { LOG(L_ERR,"ERROR:get_ssl: unable to extract SSL data " "from TLS connection\n"); return 0; } return c->extra_data;}static inline int get_cert(X509** cert, struct tcp_connection** c, struct sip_msg* msg, int my){ SSL* ssl; *cert = 0; *c = get_cur_connection(msg); if (!(*c)) { LOG(L_INFO,"INFO:tlsops:get_cert: TLS connection not found\n"); return -1; } ssl = get_ssl(*c); if (!ssl) goto err; *cert = my ? SSL_get_certificate(ssl) : SSL_get_peer_certificate(ssl); if (!*cert) { LOG(L_ERR,"ERROR:tlsops:get_cert: unable to get certificate " "from SSL structure\n"); goto err; } return 0;err: tcpconn_put(*c); return -1;}int tlsops_cipher(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags){ str cipher; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { LOG(L_INFO,"INFO:tlsops:tlsops_cipher: TLS connection not found " "in select_cipher\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; cipher.s = (char*)SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)); cipher.len = cipher.s ? strlen(cipher.s) : 0; if (cipher.len >= 1024) { LOG(L_ERR,"ERROR:tlsops:tlsops_cipher: cipher name too long\n"); goto err; } memcpy(buf, cipher.s, cipher.len); res->rs.s = buf; res->rs.len = cipher.len; res->flags = XL_VAL_STR; tcpconn_put(c); return 0;err: if (c) tcpconn_put(c); return -1;}int tlsops_bits(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags) { str bits; int b; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { LOG(L_INFO,"INFO:tlsops:tlsops_bits: TLS connection not found in " "select_bits\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; b = SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), 0); bits.s = int2str(b, &bits.len); if (bits.len >= 1024) { LOG(L_ERR,"ERROR:tlsops:tlsops_bits: bits string too long\n"); goto err; } memcpy(buf, bits.s, bits.len); res->rs.s = buf; res->rs.len = bits.len; res->ri = b; res->flags = XL_VAL_STR | XL_VAL_INT; tcpconn_put(c); return 0;err: if (c) tcpconn_put(c); return -1;}int tlsops_version(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags){ str version; static char buf[1024]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { LOG(L_INFO,"INFO:tlsops:tlsops_version: TLS connection not found " "in select_version\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; version.s = (char*)SSL_get_version(ssl); version.len = version.s ? strlen(version.s) : 0; if (version.len >= 1024) { LOG(L_ERR,"ERROR:tlsops:tlsops_version: version string too long\n"); goto err; } memcpy(buf, version.s, version.len); res->rs.s = buf; res->rs.len = version.len; res->flags = XL_VAL_STR; tcpconn_put(c); return 0;err: if (c) tcpconn_put(c); return -1;}int tlsops_desc(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags){ static char buf[128]; struct tcp_connection* c; SSL* ssl; c = get_cur_connection(msg); if (!c) { LOG(L_INFO,"INFO:tlsops:tlsops_desc: TLS connection not found in " "select_desc\n"); goto err; } ssl = get_ssl(c); if (!ssl) goto err; buf[0] = '\0'; SSL_CIPHER_description(SSL_get_current_cipher(ssl), buf, 128); res->rs.s = buf; res->rs.len = strlen(buf); res->flags = XL_VAL_STR; tcpconn_put(c); return 0;err: if (c) tcpconn_put(c); return -1; }int tlsops_cert_version(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags){ static char buf[INT2STR_MAX_LEN]; X509* cert; struct tcp_connection* c; char* version; int my; if (param->ind & CERT_PEER) { my = 0; } else if (param->ind & CERT_LOCAL) { my = 1; } else { LOG(L_CRIT,"BUG:tlsops:tlsops_version: bug in call to " "tlsops_cert_version\n"); return -1; } if (get_cert(&cert, &c, msg, my) < 0) return -1; version = int2str(X509_get_version(cert), &res->rs.len); memcpy(buf, version, res->rs.len); res->rs.s = buf; res->flags = XL_VAL_STR; if (!my) X509_free(cert); tcpconn_put(c); return 0;}/* * Check whether peer certificate exists and verify the result * of certificate verification */int tlsops_check_cert(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags){ static str succ = str_init("1"); static str fail = str_init("0"); int err; struct tcp_connection* c; SSL* ssl; X509* cert = 0; switch (param->ind) { case CERT_VERIFIED: err = X509_V_OK; break; case CERT_REVOKED: err = X509_V_ERR_CERT_REVOKED; break; case CERT_EXPIRED: err = X509_V_ERR_CERT_HAS_EXPIRED; break; case CERT_SELFSIGNED: err = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; break; default: LOG(L_CRIT,"BUG:tlsops:tlsops_check_cert: unexpected parameter " "value \"%d\"\n", param->ind); return -1; } c = get_cur_connection(msg); if (!c) return -1; ssl = get_ssl(c); if (!ssl) goto err; if ((cert = SSL_get_peer_certificate(ssl)) && SSL_get_verify_result(ssl) == err) { res->rs.s = succ.s; res->rs.len = succ.len; res->ri = 1; } else { res->rs.s = fail.s; res->rs.len = fail.len; res->ri = 0; } res->flags = XL_VAL_STR | XL_VAL_INT; if (cert) X509_free(cert); tcpconn_put(c); return 0;err: if (cert) X509_free(cert); if (c) tcpconn_put(c); return -1;}int tlsops_validity(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags){ static char buf[1024]; X509* cert; struct tcp_connection* c; BUF_MEM* p; BIO* mem = 0; ASN1_TIME* date; int my = 0; if (get_cert(&cert, &c, msg, my) < 0) return -1; switch (param->ind) { case CERT_NOTBEFORE: date = X509_get_notBefore(cert); break; case CERT_NOTAFTER: date = X509_get_notAfter(cert); break; default: LOG(L_CRIT,"BUG:tlsops:tlsops_validity: unexpected parameter value " "\"%d\"\n", param->ind); goto err; } mem = BIO_new(BIO_s_mem()); if (!mem) { LOG(L_ERR,"ERROR:tlsops:tlsops_validity: failed to create " "memory BIO\n"); goto err; } if (!ASN1_TIME_print(mem, date)) { LOG(L_ERR,"ERROR:tlsops:tlsops_validity: failed to print " "certificate date/time\n"); goto err; } BIO_get_mem_ptr(mem, &p); if (p->length >= 1024) { LOG(L_ERR,"ERROR:tlsops:tlsops_validity: Date/time too long\n"); goto err; } memcpy(buf, p->data, p->length); res->rs.s = buf; res->rs.len = p->length; res->flags = XL_VAL_STR ; BIO_free(mem); if (!my) X509_free(cert); tcpconn_put(c); return 0;err: if (mem) BIO_free(mem); if (!my) X509_free(cert); tcpconn_put(c); return -1;}int tlsops_sn(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags){ static char buf[INT2STR_MAX_LEN]; X509* cert; struct tcp_connection* c; int my, serial; char* sn; if (param->ind & CERT_PEER) { my = 0; } else if (param->ind & CERT_LOCAL) { my = 1; } else { LOG(L_CRIT,"BUG:tlsops:tlsops_sn: could not determine certificate\n"); return -1; } if (get_cert(&cert, &c, msg, my) < 0) return -1; serial = ASN1_INTEGER_get(X509_get_serialNumber(cert)); sn = int2str( serial, &res->rs.len); memcpy(buf, sn, res->rs.len); res->rs.s = buf; res->ri = serial; res->flags = XL_VAL_STR | XL_VAL_INT; if (!my) X509_free(cert); tcpconn_put(c); return 0;}int tlsops_comp(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags){ static char buf[1024]; X509* cert; struct tcp_connection* c; X509_NAME* name; X509_NAME_ENTRY* e; ASN1_STRING* asn1; int nid = NID_commonName, index, my = 0, issuer = 0, ind_local; char* elem; str text; text.s = 0; ind_local = param->ind; /* copy callback value as we modify it */ DBG("DEBUG:tlsops:tlsops_comp: ind_local = %x", ind_local); if (ind_local & CERT_PEER) { my = 0; ind_local = ind_local ^ CERT_PEER; } else if (ind_local & CERT_LOCAL) { my = 1; ind_local = ind_local ^ CERT_LOCAL; } else { LOG(L_CRIT,"BUG:tlsops:tlsops_comp: could not determine " "certificate\n"); return -1; } if (ind_local & CERT_SUBJECT) { issuer = 0; ind_local = ind_local ^ CERT_SUBJECT; } else if (ind_local & CERT_ISSUER) { issuer = 1; ind_local = ind_local ^ CERT_ISSUER; } else { LOG(L_CRIT,"BUG:tlsops:tlsops_comp: could not determine " "subject or issuer\n"); return -1; } switch(ind_local) { case COMP_CN: nid = NID_commonName; break; case COMP_O: nid = NID_organizationName; break; case COMP_OU: nid = NID_organizationalUnitName; break; case COMP_C: nid = NID_countryName; break; case COMP_ST: nid = NID_stateOrProvinceName; break; case COMP_L: nid = NID_localityName; break; default: nid = NID_undef; } if (get_cert(&cert, &c, msg, my) < 0) return -1; name = issuer ? X509_get_issuer_name(cert) : X509_get_subject_name(cert); if (!name) { LOG(L_ERR,"ERROR:tlsops:tlsops_comp: cannot extract subject or " "issuer name from peer certificate\n"); goto err; } if (nid == NID_undef) { /* dump the whole cert info into buf */ X509_NAME_oneline(name, buf, sizeof(buf)); res->rs.s = buf; res->rs.len = strlen(buf); res->flags = XL_VAL_STR; } else { index = X509_NAME_get_index_by_NID(name, nid, -1); if (index == -1) { switch(ind_local) { case COMP_CN: elem = "CommonName"; break; case COMP_O: elem = "OrganizationName"; break; case COMP_OU: elem = "OrganizationalUnitUname"; break; case COMP_C: elem = "CountryName"; break; case COMP_ST: elem = "StateOrProvinceName"; break; case COMP_L: elem = "LocalityName"; break; default: elem = "Unknown"; break; } DBG("DEBUG:tlsops:tlsops_comp: element %s not found in " "certificate subject/issuer\n", elem); goto err; } e = X509_NAME_get_entry(name, index); asn1 = X509_NAME_ENTRY_get_data(e); text.len = ASN1_STRING_to_UTF8((unsigned char**)&text.s, asn1); if (text.len < 0 || text.len >= 1024) { LOG(L_ERR,"ERROR:tlsops:tlsops_comp: failed to convert " "ASN1 string\n"); goto err; } memcpy(buf, text.s, text.len); res->rs.s = buf; res->rs.len = text.len; res->flags = XL_VAL_STR; OPENSSL_free(text.s); } if (!my) X509_free(cert); tcpconn_put(c); return 0; err: if (text.s) OPENSSL_free(text.s); if (!my) X509_free(cert); tcpconn_put(c); return -1;}int tlsops_alt(struct sip_msg *msg, xl_value_t *res, xl_param_t *param, int flags){ static char buf[1024]; int type = GEN_URI, my = 0, n, found = 0, ind_local; STACK_OF(GENERAL_NAME)* names = 0; GENERAL_NAME* nm; X509* cert; struct tcp_connection* c; str text; struct ip_addr ip; ind_local = param->ind; if (ind_local & CERT_PEER) { my = 0; ind_local = ind_local ^ CERT_PEER; } else if (ind_local & CERT_LOCAL) { my = 1; ind_local = ind_local ^ CERT_LOCAL; } else { LOG(L_CRIT,"BUG:tlsops:tlsops_alt: could not determine certificate\n"); return -1; } switch(ind_local) { case COMP_E: type = GEN_EMAIL; break; case COMP_HOST: type = GEN_DNS; break; case COMP_URI: type = GEN_URI; break; case COMP_IP: type = GEN_IPADD; break; default: LOG(L_CRIT,"BUG:tlsops:tlsops_alt: ind_local=%d\n", ind_local); return -1; } if (get_cert(&cert, &c, msg, my) < 0) return -1; names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (!names) { LOG(L_ERR,"ERROR:tlsops:tlsops_alt: cannot get certificate " "alternative subject\n"); goto err; } for (n = 0; n < sk_GENERAL_NAME_num(names); n++) { nm = sk_GENERAL_NAME_value(names, n); if (nm->type != type) continue; switch(type) { case GEN_EMAIL: case GEN_DNS: case GEN_URI: text.s = (char*)nm->d.ia5->data; text.len = nm->d.ia5->length; if (text.len >= 1024) { LOG(L_ERR,"ERROR:tlsops:tlsops_alt: alternative subject " "text too long\n"); goto err; } memcpy(buf, text.s, text.len); res->rs.s = buf; res->rs.len = text.len; res->flags = XL_VAL_STR; found = 1; break; case GEN_IPADD: ip.len = nm->d.iPAddress->length; ip.af = (ip.len == 16) ? AF_INET6 : AF_INET; memcpy(ip.u.addr, nm->d.iPAddress->data, ip.len); text.s = ip_addr2a(&ip); text.len = strlen(text.s); memcpy(buf, text.s, text.len); res->rs.s = buf; res->rs.len = text.len; res->flags = XL_VAL_STR; found = 1; break; } break; } if (!found) goto err; if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); if (!my) X509_free(cert); tcpconn_put(c); return 0; err: if (names) sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); if (!my) X509_free(cert); tcpconn_put(c); return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -