[asterisk-commits] branch oej/ami_ssl r15478 - in /team/oej/ami_ssl: ./ configs/ contrib/ssl/ in...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Mon Mar 27 21:25:08 MST 2006


Author: oej
Date: Mon Mar 27 22:25:07 2006
New Revision: 15478

URL: http://svn.digium.com/view/asterisk?rev=15478&view=rev
Log:
First commit - inclusion of code from bugtracker

Added:
    team/oej/ami_ssl/configs/ssl.conf.sample   (with props)
    team/oej/ami_ssl/contrib/ssl/
    team/oej/ami_ssl/contrib/ssl/client_ssl.c   (with props)
    team/oej/ami_ssl/contrib/ssl/client_ssl.h   (with props)
    team/oej/ami_ssl/include/asterisk/ssl_addon.h   (with props)
    team/oej/ami_ssl/ssl_addon.c   (with props)
Modified:
    team/oej/ami_ssl/Makefile
    team/oej/ami_ssl/manager.c

Modified: team/oej/ami_ssl/Makefile
URL: http://svn.digium.com/view/asterisk/team/oej/ami_ssl/Makefile?rev=15478&r1=15477&r2=15478&view=diff
==============================================================================
--- team/oej/ami_ssl/Makefile (original)
+++ team/oej/ami_ssl/Makefile Mon Mar 27 22:25:07 2006
@@ -147,7 +147,7 @@
   AGI_DIR=$(ASTVARLIBDIR)/agi-bin
 endif
 
-ASTCFLAGS=
+ASTCFLAGS=-I/usr/kerberos/include
 
 # Define this to use files larger than 2GB (useful for sound files longer than 37 hours and logfiles)
 ASTCFLAGS+=-D_FILE_OFFSET_BITS=64
@@ -234,7 +234,7 @@
 endif
 
 INCLUDE+=-Iinclude -I../include
-ASTCFLAGS+=-pipe  -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE #-DMAKE_VALGRIND_HAPPY
+ASTCFLAGS+=-pipe  -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(DEBUG) $(INCLUDE) -D_REENTRANT -D_GNU_SOURCE #-DAMI_WITH_SSL #-DMAKE_VALGRIND_HAPPY
 ASTCFLAGS+=$(OPTIMIZE)
 ASTCFLAGS+=# -Werror -Wunused
 ifeq ($(shell gcc -v 2>&1 | grep 'gcc version' | cut -f3 -d' ' | cut -f1 -d.),4)
@@ -359,7 +359,7 @@
 OBJS=io.o sched.o logger.o frame.o loader.o config.o channel.o \
 	translate.o file.o pbx.o cli.o md5.o term.o \
 	ulaw.o alaw.o callerid.o fskmodem.o image.o app.o \
-	cdr.o tdd.o acl.o rtp.o udptl.o manager.o asterisk.o \
+	cdr.o tdd.o acl.o rtp.o udptl.o manager.o ssl_addon.o asterisk.o \
 	dsp.o chanvars.o indications.o autoservice.o db.o privacy.o \
 	astmm.o enum.o srv.o dns.o aescrypt.o aestab.o aeskey.o \
 	utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
@@ -436,6 +436,10 @@
   HAVEDOT=yes
 else
   HAVEDOT=no
+endif
+
+ifeq ($(findstring AMI_WITH_SSL, $(ASTCFLAGS)), AMI_WITH_SSL)
+  LIBS+=-lssl
 endif
 
 INSTALL=install
@@ -716,6 +720,15 @@
 	@echo " + **Note** This requires that you have      +"
 	@echo " + doxygen installed on your local system    +"
 	@echo " +-------------------------------------------+"
+	@echo " +                                           +"
+	@echo " + AMI can be encrypted or unencrypted. For  +"
+	@echo " + encrypted you can either create your own  +"
+	@echo " + certificate or  use the one provided by   +"
+	@echo " + the asterisk. If you want to create your  +"
+	@echo " + own certificate, please read the ssl.txt  +"
+	@echo " + documentation in the doc directory.       +"
+	@echo " +                                           +"
+	@echo " +-------------------------------------------+"
 	@$(MAKE) -s oldmodcheck
 
 NEWMODS=$(notdir $(wildcard */*.so))
@@ -739,7 +752,7 @@
 		echo " WARNING WARNING WARNING" ;\
 	fi
 
-install: all datafiles bininstall
+install: all datafiles cert bininstall 
 	@if [ -x /usr/sbin/asterisk-post-install ]; then \
 		/usr/sbin/asterisk-post-install $(DESTDIR) . ; \
 	fi
@@ -919,6 +932,59 @@
 env:
 	env
 
+
+UTF8 := $(shell locale -c LC_CTYPE -k | grep -q charmap.*UTF-8 && echo -utf8)
+SERIAL=0
+
+cert:
+	if [ ! -f /var/lib/asterisk/certs/server.pem ]; then      \
+		umask 77 ; \
+                PEM1=`/bin/mktemp /tmp/openssl.XXXXXX` ; \
+                PEM2=`/bin/mktemp /tmp/openssl.XXXXXX` ; \
+                sudo cp ./configs/ssl.conf.sample /etc/asterisk/ssl.conf; \
+                /usr/bin/openssl req $(UTF8) -newkey rsa:1024 -keyout $$PEM1 -nodes -x509 -days 365 -out $$PEM2 -set_serial $(SERIAL)  -config /etc/asterisk/ssl.conf; \
+                cat $$PEM1 >  $@ ; \
+                echo ""    >> $@ ; \
+                cat $$PEM2 >> $@ ; \
+                cat $@ > server.pem ;\
+                sudo mkdir -p /var/lib/asterisk/certs; \
+                sudo mv $@  /var/lib/asterisk/certs/server.pem; \
+                $(RM) $$PEM1 $$PEM2 $@; \
+        fi
+
+		
+
+certificate:
+	createcert="1"; \
+	if [ -f /var/lib/asterisk/certs/server.pem ]; then 	\
+		echo -n "The certificate already exists, Do you really want to create new one(yes/no)?"; \
+		read answer;  \
+		if [ "$$answer" = "yes" ]; then \
+			echo "I am creating a new certificate, Old one is copied as server.pem.old ";\
+			sudo cp /var/lib/asterisk/certs/server.pem /var/lib/asterisk/certs/server.pem.old; \
+		elif [ "$$answer" = "no" ]; then \
+			echo "Certificate already exists, I am not creating a new certificate,";\
+			createcert="0"; \
+		else \
+			echo "You need to enter either yes or no"; \
+			createcert="0"; \
+		fi; \
+	fi; \
+	if [ "$$createcert" = "1" ]; then  \
+		umask 77 ; \
+		PEM1=`/bin/mktemp /tmp/openssl.XXXXXX` ; \
+		PEM2=`/bin/mktemp /tmp/openssl.XXXXXX` ; \
+		sudo cp ./configs/ssl.conf.sample /etc/asterisk/ssl.conf; \
+		/usr/bin/openssl req $(UTF8) -newkey rsa:1024 -keyout $$PEM1 -nodes -x509 -days 365 -out $$PEM2 -set_serial $(SERIAL)  -config /etc/asterisk/ssl.conf; \
+		cat $$PEM1 >  $@ ; \
+		echo ""    >> $@ ; \
+		cat $$PEM2 >> $@ ; \
+		cat $@ > server.pem ;\
+		sudo mkdir -p /var/lib/asterisk/certs; \
+		sudo mv $@  /var/lib/asterisk/certs/server.pem; \
+		$(RM) $$PEM1 $$PEM2 $@; \
+	fi
+
 # If the cleancount has been changed, force a make clean.
 # .cleancount is the global clean count, and .lastclean is the 
 # last clean count we had

Added: team/oej/ami_ssl/configs/ssl.conf.sample
URL: http://svn.digium.com/view/asterisk/team/oej/ami_ssl/configs/ssl.conf.sample?rev=15478&view=auto
==============================================================================
--- team/oej/ami_ssl/configs/ssl.conf.sample (added)
+++ team/oej/ami_ssl/configs/ssl.conf.sample Mon Mar 27 22:25:07 2006
@@ -1,0 +1,154 @@
+# $Id$
+#
+# OpenSSL configuration file for custom Certificate Authority. Use a
+# different openssl.cnf file to generate certificate signing requests;
+# this one is for use only in Certificate Authority operations (csr ->
+# cert, cert revocation, revocation list generation).
+#
+# Be sure to customize this file prior to use, e.g. the commonName and
+# other options under the root_ca_distinguished_name section.
+
+HOME                    = .
+RANDFILE                = $ENV::HOME/.rnd
+
+[ ca ]
+default_ca      = CA_default
+
+[ CA_default ]
+dir             = .
+# unsed at present, and my limited certs can be kept in current dir
+#certs          = $dir/certs
+new_certs_dir   = $dir/newcerts
+crl_dir         = $dir/crl
+database        = $dir/index
+
+certificate     = $dir/ca-cert.pem
+serial          = $dir/serial
+crl             = $dir/ca-crl.pem
+private_key     = $dir/private/ca-key.pem
+RANDFILE        = $dir/private/.rand
+
+x509_extensions = usr_cert
+
+# Comment out the following two lines for the "traditional"
+# (and highly broken) format.
+name_opt        = ca_default
+cert_opt        = ca_default
+
+default_crl_days= 30
+default_days    = 7300
+# if need to be compatible with older software, use weaker md5
+default_md      = sha1
+# MSIE may need following set to yes?
+preserve        = no
+
+# A few difference way of specifying how similar the request should look
+# For type CA, the listed attributes must be the same, and the optional
+# and supplied fields are just that :-)
+policy          = policy_match
+
+# For the CA policy
+[ policy_match ]
+countryName             = US
+stateOrProvinceName     = CA
+organizationName        = XYZ
+organizationalUnitName  = XYZ 
+commonName              = asterisk
+emailAddress            = root at localhost 
+
+# For the 'anything' policy
+# At this point in time, you must list all acceptable 'object'
+# types.
+[ policy_anything ]
+countryName             = optional
+stateOrProvinceName     = optional
+localityName            = optional
+organizationName        = optional
+organizationalUnitName  = optional
+commonName              = supplied
+emailAddress            = optional
+
+####################################################################
+[ req ]
+default_bits            = 2048
+default_keyfile         = ./private/ca-key.pem
+default_md              = sha1
+
+prompt                  = no
+distinguished_name      = root_ca_distinguished_name
+
+x509_extensions = v3_ca
+
+# Passwords for private keys if not present they will be prompted for
+# input_password = secret
+# output_password = secret
+
+# This sets a mask for permitted string types. There are several options. 
+# default: PrintableString, T61String, BMPString.
+# pkix   : PrintableString, BMPString.
+# utf8only: only UTF8Strings.
+# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
+# MASK:XXXX a literal mask value.
+# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
+# so use this option with caution!
+string_mask = nombstr
+
+# req_extensions = v3_req
+
+[ root_ca_distinguished_name ]
+commonName = NoSuchCA CA
+countryName = US
+stateOrProvinceName = California
+localityName = San Mateo
+0.organizationName = domain.net
+emailAddress = nobody at localhost
+
+[ usr_cert ]
+
+# These extensions are added when 'ca' signs a request.
+
+# This goes against PKIX guidelines but some CAs do it and some software
+# requires this to avoid interpreting an end user certificate as a CA.
+
+basicConstraints=CA:FALSE
+
+# PKIX recommendations harmless if included in all certificates.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid,issuer:always
+
+nsCaRevocationUrl               = https://www.sial.org/ca-crl.pem
+#nsBaseUrl
+#nsRevocationUrl
+#nsRenewalUrl
+#nsCaPolicyUrl
+#nsSslServerName
+
+[ v3_req ]
+
+# Extensions to add to a certificate request
+
+basicConstraints = CA:FALSE
+keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+
+[ v3_ca ]
+
+
+# Extensions for a typical CA
+
+# PKIX recommendation.
+subjectKeyIdentifier=hash
+authorityKeyIdentifier=keyid:always,issuer:always
+
+# This is what PKIX recommends but some broken software chokes on critical
+# extensions.
+#basicConstraints = critical,CA:true
+# So we do this instead.
+basicConstraints = CA:true
+
+[ crl_ext ]
+
+# CRL extensions.
+# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
+
+# issuerAltName=issuer:copy
+authorityKeyIdentifier=keyid:always,issuer:always

Propchange: team/oej/ami_ssl/configs/ssl.conf.sample
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/ami_ssl/configs/ssl.conf.sample
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/ami_ssl/configs/ssl.conf.sample
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/oej/ami_ssl/contrib/ssl/client_ssl.c
URL: http://svn.digium.com/view/asterisk/team/oej/ami_ssl/contrib/ssl/client_ssl.c?rev=15478&view=auto
==============================================================================
--- team/oej/ami_ssl/contrib/ssl/client_ssl.c (added)
+++ team/oej/ami_ssl/contrib/ssl/client_ssl.c Mon Mar 27 22:25:07 2006
@@ -1,0 +1,344 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2005 - 2006, Tello Corporation, Inc.
+ *
+ * Remco Treffkorn(Architect), Mahesh Karoshi(Senior Software Developer)
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief SSL for The Asterisk Management Interface - AMI
+ *
+ * Channel Management and more
+ *
+ * \ref amiconf
+ */
+
+/*! \addtogroup Group_AMI AMI functions
+*/
+/*! @{
+ Doxygen group */
+
+/*!  We use negative file descriptors for secure channels. The file descriptor
+   -1 is reseved for errors. -2 to -... are secure file descriptors. 0  to ...
+   are regular file descriptors.
+
+   The routines in here demonstrate the use of secure fd's.
+
+   NOTE: Commonly error checks for routines returning fd's are done with (value<0).
+   You must check for (value==-1) instead, since all other negative fd's now
+   are valid fd's.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <signal.h>
+//#include "asterisk/logger.h"
+
+#define BUFSIZE 1024
+
+#define EVENTBUFSIZE 10*1024
+
+#if !defined (INADDR_NONE)
+#define INADDR_NONE   ((in_addr_t)-1)
+#endif
+
+#include "client_ssl.h"
+
+SSL_CTX *cctx;
+
+static long rec_bytes = 0;
+static long sent_bytes = 0;
+static int sslfd;
+
+/*! 	This has to be called before any other function dealing with ssl.
+ *   	Initializes all the ssl related stuff here.  
+*/
+int client_init_secure(void)
+{
+	SSL_METHOD *meth;
+
+	/* client init */
+	SSLeay_add_ssl_algorithms();
+	meth = SSLv23_client_method();
+	SSL_load_error_strings();
+	cctx = SSL_CTX_new (meth);
+
+	if (!cctx) {
+		fprintf(stderr, "Failed to create a client ssl context!\n");
+	}
+	return 0;
+}
+
+/*!     Takes the negative ssl fd and returns the positive fd recieved from the os.
+ *      It goes through arrray of fixed maximum number of secured channels.
+*/
+int get_real_fd(int fd)
+{
+	if (fd<-1) {
+	fd =  -fd - 2;
+	if (fd>=0 && fd <SEC_MAX)
+	    	fd = sec_channel[fd].fd;
+	else fd = -1;
+
+	}
+	return fd;
+}
+
+/*!    Returns the SSL pointer from the fd. This structure is filled when we accept
+ *     the ssl connection and used
+ *     for reading and writing through ssl.
+*/
+SSL* get_ssl(int fd)
+{
+	SSL *ssl = NULL;
+	fd = -fd - 2;
+
+	if (fd>=0 && fd <SEC_MAX)
+		ssl = sec_channel[fd].ssl;
+	return ssl;
+}
+
+/*!    Returns the empty ssl slot. Used to save ssl information.
+*/
+int sec_getslot(void)
+{
+	int i;
+
+	for (i=0; i<SEC_MAX; i++) {
+		if(sec_channel[i].ssl==NULL)
+	    		break;
+	}
+
+	if (i==SEC_MAX) return -1;
+		return i;
+}
+
+/*!
+ *      Writes through secured ssl connection
+*/
+int m_send(int fd, const void *data, size_t len)
+{
+	sent_bytes += len;
+
+	if (fd<-1) {
+		SSL* ssl = get_ssl(fd);
+		return SSL_write(ssl, data, len);
+	}
+	return write(fd, data, len);
+}
+
+/*!
+ *      Receives data from the ssl connection.
+*/
+int m_recv(int s, void *buf, size_t len, int flags)
+{
+    int ret = 0;
+
+    if (s<-1) {
+        SSL* ssl = get_ssl(s);
+        ret = SSL_read (ssl, buf, len);
+    } else
+        ret = recv(s, buf, len, flags);
+
+    if (ret > 0)
+        rec_bytes += ret;
+
+    return ret;
+}
+
+/*!
+ *      Needs to be called instead of close() to close a socket.
+ *      It also closes the ssl meta connection.
+*/
+int close_sock(int socket)
+{
+	int ret=0;
+	SSL* ssl = NULL;
+
+	if (socket<-1) {
+		socket = -(socket + 2);
+		ssl = sec_channel[socket].ssl;
+		sec_channel[socket].ssl = NULL;
+		socket = sec_channel[socket].fd;
+	}
+
+	//printf("closing the socket: %d\n", socket);
+	ret= close(socket);
+
+	if (ssl)
+		SSL_free (ssl);
+
+	return(ret);
+}
+
+
+/*!
+ * 	Provides the regular TCP connection. 
+*/
+
+int connectsock(const char *host, const char *service, const char *protocol)
+{
+	struct hostent *phe;
+	struct servent *pse;
+	struct protoent *ppe;
+	struct sockaddr_in sin;
+	int s, type, one = 1;
+
+	memset((char *) &sin, 0, sizeof(sin));
+	sin.sin_family = AF_INET;
+	if ((pse = getservbyname(service, protocol)))
+		sin.sin_port = htons(ntohs((unsigned short) pse->s_port));
+	else if ((sin.sin_port = htons((unsigned short) atoi(service))) == 0)
+		return -1;
+	if ((phe = gethostbyname(host)))
+		memcpy((char *) &sin.sin_addr, phe->h_addr, phe->h_length);
+	else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE)
+		return -1;
+	if ((ppe = getprotobyname(protocol)) == 0)
+		return -1;
+	if (strcmp(protocol, "udp") == 0)
+		type = SOCK_DGRAM;
+	else
+		type = SOCK_STREAM;
+
+	if ((s = socket(PF_INET, type, ppe->p_proto)) < 0)
+		return -1;
+	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one))==-1) {
+		(void)close(s);
+		return -1;
+	}
+	if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+		(void)close(s);
+		return -1;
+	}
+	return s;
+}
+
+/*!
+*  Connects securly to the remote end. Initializes lots of ssl stuff. 
+*  Returns the negative fd. Purposefully negative fd's are returned in order to
+*  differentiate between ssl and non-ssl connections. 
+*/
+int sec_connectTCP(char *host, char *service)
+{
+	int s, fd, err=-1;
+	SSL* ssl;
+
+	if ((fd=connectsock(host, service, "tcp"))==-1)
+		return -1;
+	//printf("socket created: %d\n", fd);
+
+	if ((s=sec_getslot())!=-1) {	/* find a slot for the ssl handle */
+		sec_channel[s].fd = fd;		/* remember the real fd */
+
+	if((ssl=SSL_new(cctx))) {	/* get a new ssl */
+	    	sec_channel[s].ssl = ssl;
+	    	SSL_set_fd(ssl, fd);	/* and attach the real fd */
+	    	err = SSL_connect(ssl);	/* now try and connect */
+	}
+	fd = -(s+2);			/* offset by two and negate */
+					/* this tells us it is a ssl fd */
+	}
+
+	if (err==-1) {
+		close_sock(fd);			/* that frees the ssl too */
+		fd = -1;
+	}
+
+	return fd;
+}
+
+int main(int argc, char* argv[])
+{
+	char recvBuffer[BUFSIZE];
+	char eventBuffer[EVENTBUFSIZE];
+	char event[EVENTBUFSIZE];
+	char actionBuf[500];
+	char *strptr;
+	char hostname[100], port[100], username[100], password[100];
+	int pos;
+	fd_set listeners;
+	struct timeval tv;
+
+	if (argc == 5){
+		strcpy(hostname,argv[1]);
+		strcpy(port,argv[2]);
+		strcpy(username,argv[3]);
+		strcpy(password, argv[4]);
+	} else {
+		printf("Usage: ./client_ssl asteriskhostname portnumber username password\n");
+		exit(0);
+	}
+        signal(SIGINT, catch_int);
+	client_init_secure();
+	if((sslfd = sec_connectTCP(hostname, port)) == -1) {
+		printf("SSL connection to asterisk failed : \n"); 
+		exit(0);
+	}
+	strcpy(actionBuf, "Action: Login\r\n");
+	strcat(actionBuf, "Username: ");
+	strcat(actionBuf, username);
+	strcat(actionBuf, "\r\n");
+	strcat(actionBuf, "Secret: ");
+	strcat(actionBuf, password);
+	strcat(actionBuf, "\r\n\r\n");
+        m_recv(sslfd, &recvBuffer, BUFSIZE - 1, 0);
+        if ((strptr = strstr(recvBuffer, "\r\n\r\n"))) {
+        	pos = strptr - recvBuffer;     // Length of event text...
+        	strncpy(event,recvBuffer,pos);
+	}
+	printf("%s\n", event);
+	m_send(sslfd, actionBuf, BUFSIZE); 
+	printf("The event sent to asterisk:\n %s", actionBuf);
+	tv.tv_sec = 1;
+        tv.tv_usec = 0;
+	while(1) {
+		FD_ZERO(&listeners);
+		FD_SET(get_real_fd(sslfd), &listeners);
+		int ready_fdescriptors = select (get_real_fd(sslfd) + 1, &listeners, NULL, NULL, &tv);
+
+		if (ready_fdescriptors < 0 ) {
+			printf("select returned error, This should not happen: \n");
+			close(get_real_fd(sslfd));
+			exit(0);
+		} else if (ready_fdescriptors == 0) {
+			continue;
+		}
+		if(m_recv(sslfd, &recvBuffer, BUFSIZE - 1, 0) == 0) {
+			exit(0);
+		} else {
+			if ((strptr = strstr(recvBuffer, "\r\n\r\n"))) {
+				pos = strptr - recvBuffer;     // Length of event text...
+				strncpy(event,recvBuffer,pos);
+			}
+	        	printf("%s\r\n", event);
+		}
+	}
+}
+
+void catch_int(int sig_num)
+{
+    /* re-set the signal handler again to catch_int, for next time */
+    signal(SIGINT, catch_int);
+    printf("Ctrl C pressed, closing the socket connection fd = %d\n", sslfd);
+    close_sock(sslfd);
+    exit(0);
+}

Propchange: team/oej/ami_ssl/contrib/ssl/client_ssl.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/ami_ssl/contrib/ssl/client_ssl.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/ami_ssl/contrib/ssl/client_ssl.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/oej/ami_ssl/contrib/ssl/client_ssl.h
URL: http://svn.digium.com/view/asterisk/team/oej/ami_ssl/contrib/ssl/client_ssl.h?rev=15478&view=auto
==============================================================================
--- team/oej/ami_ssl/contrib/ssl/client_ssl.h (added)
+++ team/oej/ami_ssl/contrib/ssl/client_ssl.h Mon Mar 27 22:25:07 2006
@@ -1,0 +1,80 @@
+/*
+ * client_ssl: encrypts the asterisk management interface
+ *
+ * Copyrights:
+ *
+ * Contributors:
+ * Mahesh Karoshi and Remco Treffkorn(Architect)
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ */
+
+#ifndef _CLIENT_SSL_H_
+#define _CLIENT_SSL_H_
+#define SEC_MAX 8
+
+#include <openssl/ssl.h>
+//SSL_CTX *cctx;
+
+/*
+This data structure holds the additional SSL data needed to use the ssl functions.
+The negative fd is used as an index into this data structure (after processing).
+
+Choose SEC_MAX to be impossibly large for the application.
+*/
+
+struct {
+	int fd;
+	SSL* ssl;
+} sec_channel[SEC_MAX];
+/*
+   this has to be called before any other function dealing with ssl.
+*/
+
+int client_init_secure(void);
+
+// Returns the real fd, that is received from os, when we accept the connection.
+
+int get_real_fd(int fd);
+
+/*
+   Sends the data over secured or unsecured connections.
+*/
+int m_send(int fd, const void *data, size_t len);
+
+/*
+   Receives the connection from either ssl or fd.
+*/
+int m_recv(int s, void *buf, size_t len, int flags);
+
+/*
+   Needs to be called instead of close() to close a socket.
+   It also closes the ssl meta connection.
+*/
+int close_sock(int socket);
+
+/*       
+   provides the ssl connect api
+*/	
+int sec_connectTCP(char *host, char *service);
+
+// returns the ssl structure from the fd.
+SSL* get_ssl(int fd);
+
+/*
+   Returns the availabe security slot. This restricts the maximun number of security connection,
+   the asterisk server can have for AMI.
+*/
+int sec_getslot(void);
+
+/* 
+ * connect with SSL
+*/
+int connectsock(const char *host, const char *service, const char *protocol);
+
+void catch_int(int sig_num);
+#endif
+

Propchange: team/oej/ami_ssl/contrib/ssl/client_ssl.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/ami_ssl/contrib/ssl/client_ssl.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/ami_ssl/contrib/ssl/client_ssl.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/oej/ami_ssl/include/asterisk/ssl_addon.h
URL: http://svn.digium.com/view/asterisk/team/oej/ami_ssl/include/asterisk/ssl_addon.h?rev=15478&view=auto
==============================================================================
--- team/oej/ami_ssl/include/asterisk/ssl_addon.h (added)
+++ team/oej/ami_ssl/include/asterisk/ssl_addon.h Mon Mar 27 22:25:07 2006
@@ -1,0 +1,91 @@
+/*
+ * ssl_addon: Encrypts the asterisk management interface
+ *
+ * Copyrights:
+ * Copyright (C) 2005-2006, Tello Corporation, Inc.
+ *
+ * Contributors:
+ * Remco Treffkorn(Architect) and Mahesh Karoshi
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser (Library) General Public License
+ *
+ * Copyright on this file is disclaimed to Digium for inclusion in Asterisk
+ */
+
+#ifndef _SSL_ADDON_H_
+#define _SSL_ADDON_H_
+
+#include <openssl/ssl.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+   This data structure holds the additional SSL data needed to use the ssl functions.
+   The negative fd is used as an index into this data structure (after processing).
+   Choose SEC_MAX to be impossibly large for the application.
+*/
+#define SEC_MAX 8
+struct {
+    int fd;
+    SSL* ssl;
+} sec_channel[SEC_MAX];
+
+/*!
+   this has to be called before any other function dealing with ssl.
+*/
+int init_secure(char* certfile);
+
+/*!
+   Returns the real fd, that is received from os, when we accept the connection.
+*/
+int get_real_fd(int fd);
+
+/*! 
+   Returns the ssl structure from the fd.  
+*/
+SSL *get_ssl(int fd);
+
+/*!
+   Returns the availabe security slot. This restricts the maximun number of security connection, 
+   the asterisk server can have for AMI. 
+*/
+int sec_getslot(void);
+
+/*!
+   Accepts the connection, if the security is enabled it returns the negative fd. -1 is flase, -2, -3 
+   etc are ssl connections. 
+*/ 
+int saccept(int s);
+
+/*! 
+   Sends the data over secured or unsecured connections. 
+*/ 
+int m_send(int fd, const void *data, size_t len);
+
+
+/*!
+   Receives the connection from either ssl or fd.
+*/
+int m_recv(int s, void *buf, size_t len, int flags);
+
+
+/*!
+  Needs to be called instead of close() to close a socket.
+  It also closes the ssl meta connection.
+*/
+
+int close_sock(int socket);
+
+int errexit(char s[]);
+
+int is_encrypt_request(int sslclhellotimeout, int fd);
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif

Propchange: team/oej/ami_ssl/include/asterisk/ssl_addon.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/oej/ami_ssl/include/asterisk/ssl_addon.h
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/oej/ami_ssl/include/asterisk/ssl_addon.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/oej/ami_ssl/manager.c
URL: http://svn.digium.com/view/asterisk/team/oej/ami_ssl/manager.c?rev=15478&r1=15477&r2=15478&view=diff
==============================================================================
--- team/oej/ami_ssl/manager.c (original)
+++ team/oej/ami_ssl/manager.c Mon Mar 27 22:25:07 2006
@@ -64,6 +64,9 @@
 #include "asterisk/md5.h"
 #include "asterisk/acl.h"
 #include "asterisk/utils.h"
+#ifdef AMI_WITH_SSL
+#include "ssl_addon.h"
+#endif
 
 struct fast_originate_helper {
 	char tech[AST_MAX_MANHEADER_LEN];
@@ -81,6 +84,11 @@
 	struct ast_variable *vars;
 };
 
+#ifdef AMI_WITH_SSL
+static int sslclhellotimeout = 200;
+static int acceptencryptedconnection = 0;
+static int acceptunencryptedconnection = 0;
+#endif
 static int enabled = 0;
 static int portno = DEFAULT_MANAGER_PORT;
 static int asock = -1;
@@ -154,7 +162,11 @@
 	int res=0;
 	struct pollfd fds[1];
 	while(len) {
+#ifdef AMI_WITH_SSL
+		res = m_send(fd, s, len);
+#else
 		res = write(fd, s, len);
+#endif
 		if ((res < 0) && (errno != EAGAIN)) {
 			return -1;
 		}
@@ -163,7 +175,11 @@
 		s += res;
 		res = 0;
 		if (len) {
+#ifdef AMI_WITH_SSL
+			fds[0].fd = get_real_fd(fd);
+#else
 			fds[0].fd = fd;
+#endif
 			fds[0].events = POLLOUT;
 			/* Wait until writable again */
 			res = poll(fds, 1, timeoutms);
@@ -321,8 +337,12 @@
 static void free_session(struct mansession *s)
 {
 	struct eventqent *eqe;
+#ifdef AMI_WITH_SSL
+	close_sock(s->fd);
+#else
 	if (s->fd > -1)
 		close(s->fd);
+#endif
 	ast_mutex_destroy(&s->__lock);
 	while(s->eventq) {
 		eqe = s->eventq;
@@ -1413,6 +1433,10 @@
 		s->inlen = 0;
 	}
 	fds[0].fd = s->fd;
+#ifdef AMI_WITH_SSL
+	fds[0].fd = get_real_fd(s->fd);
+#endif
+
 	fds[0].events = POLLIN;
 	do {
 		res = poll(fds, 1, -1);
@@ -1426,7 +1450,11 @@
 	 		return -1;
 		} else if (res > 0) {
 			ast_mutex_lock(&s->__lock);
+#ifdef AMI_WITH_SSL
+			res = m_recv(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen, 0);
+#else
 			res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen);
+#endif
 			ast_mutex_unlock(&s->__lock);
 			if (res < 1)
 				return -1;
@@ -1509,6 +1537,31 @@
 				ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
 			}
 		}
+#ifdef AMI_WITH_SSL
+		int is_encrytped = is_encrypt_request(sslclhellotimeout, as);
+		if( is_encrytped > 0) {
+			if (! acceptencryptedconnection ) {
+				ast_log(LOG_NOTICE, "Accepting encrypted connection disabled, closing the connection \n");
+				close_sock(as);
+                                continue;
+			} else {
+                        	if((as = saccept(as)) >= 0 ) {
+                                	ast_log(LOG_NOTICE, "Can't accept the ssl connection, since SSL init has failed for certificate reason\n");
+                                	close_sock(as);
+                                	continue;
+				}
+                        }
+		} else if (is_encrytped == -1) {
+		   	ast_log(LOG_NOTICE, "SSL version 2 is unsecured, we don't support it\n");
+			close_sock(as);
+			continue;
+		}
+		if ( (! acceptunencryptedconnection) && (as >= 0)) {
+			ast_log(LOG_NOTICE, "Unencrypted connections are not accepted and we received an unencrypted connection request\n");
+			close_sock(as);
+			continue;
+		}
+#endif
 		s = malloc(sizeof(struct mansession));
 		if (!s) {
 			ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno));
@@ -1520,8 +1573,13 @@
 
 		if(! block_sockets) {
 			/* For safety, make sure socket is non-blocking */
+#ifdef AMI_WITH_SSL
+			flags = fcntl(get_real_fd(as), F_GETFL);
+			fcntl(get_real_fd(as), F_SETFL, flags | O_NONBLOCK);
+#else
 			flags = fcntl(as, F_GETFL);
 			fcntl(as, F_SETFL, flags | O_NONBLOCK);
+#endif
 		}
 		ast_mutex_init(&s->__lock);
 		s->fd = as;
@@ -1710,6 +1768,9 @@
 {
 	struct ast_config *cfg;
 	char *val;
+#ifdef AMI_WITH_SSL
+	char certfile[1000], ssltimeout[1000];
+#endif
 	int oldportno = portno;
 	static struct sockaddr_in ba;
 	int x = 1;
@@ -1786,6 +1847,44 @@
 		ast_log(LOG_WARNING, "Unable to change management port / enabled\n");
 #endif
 	}
+
+#ifdef AMI_WITH_SSL
+        /* Parsing the certificate directory */
+        if ((val = ast_variable_retrieve(cfg, "general", "certfile"))) {
+		if (sscanf(val, "%s", (char *)certfile) != 1) {
+			ast_log(LOG_WARNING, "Certificate directory not found, assigning default directory\n");
+                       	strcpy((char *)certfile, "/var/lib/asterisk/certs/server.pem");
+		} 
+        } else {
+		strcpy((char *)certfile, "/var/lib/asterisk/certs/server.pem");
+	}
+	if ((val = ast_variable_retrieve(cfg, "general", "sslclienthellotimeout"))) {
+		if (sscanf(val, "%s", (char *)ssltimeout) != 1) {
+			sslclhellotimeout = 500;
+			ast_log(LOG_NOTICE, "Failed to read sslclhellotime\n");
+		} else {
+			sslclhellotimeout = atoi(ssltimeout);
+			ast_log(LOG_NOTICE, "sslclhellotime = %d", sslclhellotimeout);
+		}
+	} else {
+	    	sslclhellotimeout = 500;
+	}
+	val = ast_variable_retrieve(cfg, "general", "acceptencryptedconnection");
+        if (val) {
+               	acceptencryptedconnection = ast_true(val);
+		ast_log(LOG_NOTICE, "acceptencryptedconnection = %d", acceptencryptedconnection);
+	} else {
+		acceptencryptedconnection = -1;
+	}
+	val = ast_variable_retrieve(cfg, "general", "acceptunencryptedconnection");
+	if (val) {
+		acceptunencryptedconnection =  ast_true(val);
+		ast_log(LOG_NOTICE, "acceptunencryptedconnection = %d", acceptunencryptedconnection);
+	} else {
+		acceptunencryptedconnection = -1;
+	}
+        init_secure(certfile); 
+#endif
 	ast_config_destroy(cfg);
 	
 	/* If not enabled, do nothing */
@@ -1823,3 +1922,4 @@
 	manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n");
 	return init_manager();
 }
+

Added: team/oej/ami_ssl/ssl_addon.c
URL: http://svn.digium.com/view/asterisk/team/oej/ami_ssl/ssl_addon.c?rev=15478&view=auto
==============================================================================
--- team/oej/ami_ssl/ssl_addon.c (added)
+++ team/oej/ami_ssl/ssl_addon.c Mon Mar 27 22:25:07 2006
@@ -1,0 +1,306 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2005, Tello Corporation, Inc.
+ *
+ * Remco Treffkorn(Architect) and Mahesh Karoshi(Senior Software Developer)
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief SSL for The Asterisk Management Interface - AMI
+ *
+ * Channel Management and more
+ *
+ * \ref amiconf
+ */
+
+/*! \addtogroup Group_AMI AMI functions
+*/
+/*! @{
+ Doxygen group */
+
+/*!  We use negative file descriptors for secure channels. The file descriptor
+   -1 is reseved for errors. -2 to -... are secure file descriptors. 0  to ...
+   are regular file descriptors.
+
+   The routines in here demonstrate the use of secure fd's.
+
+   NOTE: Commonly error checks for routines returning fd's are done with (value<0).
+   You must check for (value==-1) instead, since all other negative fd's now
+   are valid fd's.
+*/
+#ifdef AMI_WITH_SSL
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+#include <stdio.h> 
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include "asterisk/logger.h"
+#include "asterisk/config.h"
+
+#include "asterisk.h"
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "ssl_addon.h"
+SSL_CTX *sctx;
+static long rec_bytes;
+static long sent_bytes;
+static int ssl_initialized;
+
+
+/*! this has to be called before any other function dealing with ssl.
+   Initializes all the ssl related stuff here.  */
+int init_secure(char *certfile)
+{
+    	SSL_METHOD *meth;
+
+	SSLeay_add_ssl_algorithms();
+	SSL_load_error_strings();
+
+	/* server init */
+	meth = SSLv23_server_method();
+	sctx = SSL_CTX_new(meth);
+
+	if (!sctx) {
+		return errexit("Failed to create a server ssl context!");
+	}
+
+	if (SSL_CTX_use_certificate_file(sctx, certfile, SSL_FILETYPE_PEM) <= 0) {
+		return errexit("Failed to use the certificate file!");
+	}
+
+	if (SSL_CTX_use_PrivateKey_file(sctx, certfile, SSL_FILETYPE_PEM) <= 0) {
+		return errexit("Failed to use the key file!\n");
+	}
+
+	if (!SSL_CTX_check_private_key(sctx)) {
+		return errexit("Private key does not match the certificate public key");
+	}
+	ssl_initialized = 1;
+	return 0;
+}
+
+/*!     Takes the negative ssl fd and returns the positive fd recieved from the os. 
+ * 	It goes through arrray of fixed maximum number of secured channels. 
+*/
+int get_real_fd(int fd)
+{
+	if (fd<-1) {
+		fd =  -fd - 2;
+		if (fd>=0 && fd <SEC_MAX)
+	    		fd = sec_channel[fd].fd;
+		else fd = -1;
+
+	}
+	return fd;
+}
+
+/*!    Returns the SSL pointer from the fd. This structure is filled when we accept 
+ *     the ssl connection and used 
+ *     for reading and writing through ssl.
+*/
+SSL *get_ssl(int fd)
+{
+	SSL *ssl = NULL;
+
+	fd = -fd - 2;
+
+	if (fd>=0 && fd <SEC_MAX)
+		ssl = sec_channel[fd].ssl;
+
+	return ssl;
+}
+
+/*!    Returns the empty ssl slot. Used to save ssl information.
+*/
+int sec_getslot(void)
+{
+	int i;
+
+	for (i=0; i<SEC_MAX; i++) {
+		if(sec_channel[i].ssl==NULL)
+	    		break;
+	}
+
+	if (i==SEC_MAX) return -1;
+		return i;
+}
+
+/*!     Accepts the ssl connection. Retrurns the negative fd. negative fd's are 
+ *	choosen to differentiate between ssl and non-ssl connections. positive 
+ *	fd's are used for non-ssl connections and negative fd's are used for ssl 
+ *	connections. So we purposefully calculate and return negative fds. 
+ *	You can always get positive fd by calling get_real_fd(negative fd). 
+ *	The positive fd's are required for system calls.
+ *
+*/
+int saccept(int s)
+{
+	int fd, err;
+	SSL* ssl;
+
+	if (!ssl_initialized)
+		return s;
+
+	if (((fd=sec_getslot())!=-1))  {
+		ssl=SSL_new(sctx);
+		SSL_set_fd(ssl, s);
+		sec_channel[fd].ssl = ssl;	/* remember ssl */
+		sec_channel[fd].fd = s;		/* remember the real fd */
+		do{
+			err = SSL_accept(ssl);
+			err = SSL_get_error(ssl, err);
+		}while( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE);
+
+		SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+		ast_log(LOG_DEBUG, "ssl_addon: Connection accepted");
+
+		err=1;
+
+		fd = -(fd+2);
+
+		if (err!=1 || !ssl) {
+		    /* it did not work */
+		    sec_channel[fd].ssl = NULL;	/* free the slot */
+		    fd = -1;
+		}
+	}
+	return fd;
+}
+
+/*!	
+ *	Writes through secured ssl connection 
+*/
+int m_send(int fd, const void *data, size_t len)
+{
+	sent_bytes += len;
+
+	if (fd<-1) {
+		SSL* ssl = get_ssl(fd);
+		return SSL_write(ssl, data, len);
+	}
+	return write(fd, data, len);
+}
+
+/*!
+ *	Receives data from the ssl connection. 
+*/
+int m_recv(int s, void *buf, size_t len, int flags)
+{
+	int ret = 0;
+
+	if (s<-1) {
+		SSL* ssl = get_ssl(s);
+		ret = SSL_read (ssl, buf, len);
+	} else
+		ret = recv(s, buf, len, flags);
+
+	if (ret > 0)
+		rec_bytes += ret;
+
+	ast_log(LOG_DEBUG, "ssl_addon: Received data from ssl\n");
+	return ret;
+}
+
+
+/*!
+	Needs to be called instead of close() to close a socket.
+	It also closes the ssl meta connection.
+*/
+
+int close_sock(int socket)
+{
+	int ret=0;
+	SSL* ssl = NULL;
+
+	if (socket < -1) {
+		socket = - socket - 2;
+
+		ssl = sec_channel[socket].ssl;
+		sec_channel[socket].ssl = NULL;
+		socket = sec_channel[socket].fd;
+	}
+
+	ret= close(socket);
+
+	if (ssl)
+		SSL_free (ssl);
+
+	return(ret);
+}
+
+/*! This process cannot continue without fixing this error. 
+*/
+int errexit(char s[])
+{
+    	ast_log(LOG_NOTICE, "ssl_addon: %s", s);
+	return -1;
+}
+
+/*!  Checks whether the client is requesting an ssl encrypted connection or not. If its encrypted
+ *   request we expect "Client Hello" in the beginning of the message and ssl version 2.
+ *   This can be verified by checking buf[0x02], buf[0x03] and buf[0x04]. If the contents are
+ *   0x01, 0x00, 0x02, then its an ssl packet with content "Client Hello", "SSL version 2".
+ *   For SSL version 3, we might need to check for 0x01, 0x00, 0x03.
+ *
+*/
+int is_encrypt_request(int sslclhellotimeout, int fd)
+{
+        fd_set listeners;
+        struct timeval tv;
+        char buf[1024];
+
+        tv.tv_sec = 0;
+        tv.tv_usec = sslclhellotimeout * 1000;
+
+        FD_ZERO(&listeners);
+        FD_SET(fd, &listeners);
+
+        int ready_fdescriptors = select (fd + 1, &listeners, NULL, NULL, &tv);
+
+        if (ready_fdescriptors < 0 ) {
+                ast_log(LOG_WARNING,"select returned error, This should not happen: \n");
+                return 0;
+        } else if (ready_fdescriptors == 0) {
+                return 0;
+        }
+        int ret = recv(fd, buf, 100, MSG_PEEK);
+        if(ret > 0) {
+	    	/* check for sslv3  or tls*/
+	    	if ((buf[0x00] == 0x16) && (buf[0x01] == 0x03) &&
+			/* for tls buf[0x02] = 0x01 and ssl v3 buf[0x02] = 0x02 */
+			((buf[0x02] == 0x00) || (buf[0x02] == 0x01))) {
+		    	ast_log(LOG_DEBUG, "Received a SSL request\n");
+			return 1;
+		/* check for sslv23_client_method */
+		} else if ((buf[0x02] == 0x01) && (buf[0x03] == 0x03) && (buf[0x04] == 0x01)) {
+		    	ast_log(LOG_DEBUG, "Received a SSL request for SSLv23_client_method()\n");
+			return 1;
+		}
+		/* check for sslv2 and return -1 */
+		else if ((buf[0x02] == 0x01) && (buf[0x03] == 0x00) && (buf[0x04] == 0x02)) {
+		    	return -1;
+		}
+        }
+        return 0;
+}
+#endif


[... 12 lines stripped ...]


More information about the asterisk-commits mailing list