📄 tport_tls.c
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@CFILE tport_tls.c * @brief TLS interface * * @author Mikko Haataja <ext-Mikko.A.Haataja@nokia.com> * @author Pekka Pessi <ext-Pekka.Pessi@nokia.com> * * Copyright 2001, 2002 Nokia Research Center. All rights reserved. * */#include <assert.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/time.h>#include <sys/types.h>#include <unistd.h>#include <signal.h>#define OPENSSL_NO_KRB5 oh-no#include <openssl/lhash.h>#include <openssl/bn.h>#include <openssl/x509.h>#include <openssl/x509v3.h>#include <openssl/ssl.h>#include <openssl/err.h>#include <openssl/pem.h>#include <openssl/rand.h>#include <openssl/bio.h>#include <openssl/opensslv.h>#include <poll.h>#include "tport_tls.h"char const tls_version[] = OPENSSL_VERSION_TEXT;enum { tls_master, tls_slave };struct tls_s { SSL_CTX *ctx; SSL *con; BIO *bio_con; BIO *bio_err; int type; int verified; /* Receiving */ int read_events; void *read_buffer; int read_buffer_len; /* Sending */ int write_events; void *write_buffer; int write_buffer_len; /* Host names */ char *hosts[TLS_MAX_HOSTS + 1];};enum { tls_buffer_size = 16384 };statictls_t *tls_create(int type){ tls_t *tls = calloc(1, sizeof(*tls)); if (tls) tls->type = type; return tls;}staticvoid tls_set_default(tls_issues_t *i){ i->verify_depth = i->verify_depth == 0 ? 2 : i->verify_depth; i->cert = i->cert ? i->cert : "agent.pem"; i->key = i->key ? i->key : i->cert; i->randFile = i->randFile ? i->randFile : "tls_seed.dat"; i->CAfile = i->CAfile ? i->CAfile : "cafile.pem"; i->cipher = i->cipher ? i->cipher : "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"; /* Default SIP cipher */ /* "RSA-WITH-AES-128-CBC-SHA"; */ /* RFC-2543-compatibility ciphersuite */ /* TLS_RSA_WITH_3DES_EDE_CBC_SHA; */}staticint tls_verify_cb(int ok, X509_STORE_CTX *store){ char data[256]; 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);#if nomore 509_NAME_oneline(X509_get_subject_name(cert), data, 256); fprintf(stderr,"depth=%d %s\n",depth,data);#endif if (!ok) { fprintf(stderr, "-Error with certificate at depth: %i\n", depth); X509_NAME_oneline(X509_get_issuer_name(cert), data, 256); fprintf(stderr, " issuer = %s\n", data); X509_NAME_oneline(X509_get_subject_name(cert), data, 256); fprintf(stderr, " subject = %s\n", data); fprintf(stderr, " err %i:%s\n", err, X509_verify_cert_error_string(err)); } return 1; /* Always return "ok" */}staticint tls_init_context(tls_t *tls, tls_issues_t const *ti){ static int initialized = 0; if (!initialized) { initialized = 1; SSL_library_init(); SSL_load_error_strings(); if (ti->randFile && !RAND_load_file(ti->randFile, 1024 * 1024)) { if (ti->configured > 1) { BIO_printf(tls->bio_err, "%s: cannot open randFile %s\n", "tls_init_context", ti->randFile); ERR_print_errors(tls->bio_err); } /* errno = EIO; */ /* return -1; */ } } /* Avoid possible SIGPIPE when sending close_notify */ signal(SIGPIPE, SIG_IGN); if (tls->bio_err == NULL) tls->bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); if (tls->ctx == NULL) { SSL_METHOD *meth; /* meth = SSLv3_method(); */ /* meth = SSLv23_method(); */ if (ti->version) meth = TLSv1_method(); else meth = SSLv23_method(); tls->ctx = SSL_CTX_new(meth); } if (tls->ctx == NULL) { ERR_print_errors(tls->bio_err); errno = EIO; return -1; } if (!SSL_CTX_use_certificate_file(tls->ctx, ti->cert, SSL_FILETYPE_PEM)) { if (ti->configured > 0) { BIO_printf(tls->bio_err, "%s: invalid certificate: %s\n", "tls_init_context", ti->cert); ERR_print_errors(tls->bio_err);#if require_client_certificate errno = EIO; return -1;#endif } } if (!SSL_CTX_use_PrivateKey_file(tls->ctx, ti->key, SSL_FILETYPE_PEM)) { if (ti->configured > 0) { ERR_print_errors(tls->bio_err);#if require_client_certificate errno = EIO; return -1;#endif } } if (!SSL_CTX_check_private_key(tls->ctx)) { if (ti->configured > 0) { BIO_printf(tls->bio_err, "Private key does not match the certificate public key\n"); }#if require_client_certificate errno = EIO; return -1;#endif } if (!SSL_CTX_load_verify_locations(tls->ctx, ti->CAfile, ti->CApath)) { if (ti->configured > 0) ERR_print_errors(tls->bio_err); errno = EIO; return -1; } SSL_CTX_set_verify_depth(tls->ctx, ti->verify_depth); SSL_CTX_set_verify(tls->ctx, getenv("SSL_VERIFY_PEER") ? SSL_VERIFY_PEER : SSL_VERIFY_NONE /* SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */, tls_verify_cb); if (!SSL_CTX_set_cipher_list(tls->ctx, ti->cipher)) { BIO_printf(tls->bio_err,"error setting cipher list\n"); ERR_print_errors(tls->bio_err); errno = EIO; return -1; } return 0;}void tls_free(tls_t *tls){ int k; if (!tls) return; if (tls->read_buffer) free(tls->read_buffer), tls->read_buffer = NULL; if (tls->con != NULL) SSL_shutdown(tls->con); if (tls->ctx != NULL && tls->type != tls_slave) SSL_CTX_free(tls->ctx); if (tls->bio_con != NULL) BIO_free(tls->bio_con); if (tls->bio_err != NULL && tls->type != tls_slave) BIO_free(tls->bio_err); for (k = 0; k < TLS_MAX_HOSTS; k++) free(tls->hosts[k]), tls->hosts[k] = NULL; free(tls);}int tls_get_socket(tls_t *tls){ int sock = -1; if (tls != NULL && tls->bio_con != NULL) BIO_get_fd(tls->bio_con, &sock); return sock;}tls_t *tls_init_master(tls_issues_t *ti){ /* Default id in case RAND fails */ unsigned char sessionId[32] = "sofia/tls"; tls_t *tls; signal(SIGPIPE, SIG_IGN); /* Ignore spurios SIGPIPE from OpenSSL */ tls_set_default(ti); if (!(tls = tls_create(tls_master))) return NULL; if (tls_init_context(tls, ti) < 0) { int err = errno; tls_free(tls); errno = err; return NULL; } RAND_pseudo_bytes(sessionId, sizeof(sessionId)); SSL_CTX_set_session_id_context(tls->ctx, (void*) sessionId, sizeof(sessionId)); if (ti->CAfile != NULL) SSL_CTX_set_client_CA_list(tls->ctx, SSL_load_client_CA_file(ti->CAfile));#if 0 if (sock != -1) { tls->bio_con = BIO_new_socket(sock, BIO_NOCLOSE); if (tls->bio_con == NULL) { BIO_printf(tls->bio_err, "tls_init_master: BIO_new_socket failed\n"); ERR_print_errors(tls->bio_err); tls_free(tls); errno = EIO; return NULL; } }#endif return tls;}#if 0static int tls_accept(tls_t *tls){ int ret = SSL_accept(tls->con); int verify_result; if (ret <= 0) { int err = SSL_get_error(tls->con, ret); switch(err) { case SSL_ERROR_WANT_READ: return errno = EAGAIN, tls->read_events = POLLIN, 0; case SSL_ERROR_WANT_WRITE: return errno = EAGAIN, tls->read_events = POLLOUT, 0; default: BIO_printf(tls->bio_err, "SSL_connect failed: %d %s\n", err, ERR_error_string(err, NULL)); ERR_print_errors(tls->bio_err); return -1; } } verify_result = SSL_get_verify_result(tls->con); if (verify_result != X509_V_OK) { BIO_printf(tls->bio_err, "Client certificate doesn't verify: %s\n", X509_verify_cert_error_string(verify_result));#if 0 tls_free(tls); return NULL;#endif } if (SSL_get_peer_certificate(tls->con) == NULL) { BIO_printf(tls->bio_err, "Client didn't send certificate\n");#if 0 tls_free(tls); return NULL;#endif }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -