From f616c74150b52706ea2ca144ce359fad8c853d70 Mon Sep 17 00:00:00 2001 From: cameronrich Date: Thu, 1 Feb 2007 08:31:32 +0000 Subject: [PATCH] added versioning/fragmentation git-svn-id: svn://svn.code.sf.net/p/axtls/code/trunk@56 9a5d90b5-6617-0410-8a86-bb477d3ed2e3 --- Makefile | 7 +- README | 4 +- bindings/csharp/axTLS.cs | 8 + bindings/generate_SWIG_interface.pl | 1 + bindings/generate_interface.pl | 1 + bindings/java/SSLUtil.java | 8 + bindings/vbnet/axTLSvb.vb | 4 + config/axhttpd.aip | 94 ++------ config/linuxconfig | 1 + config/win32config | 1 + docsrc/doco_footer.html | 2 +- httpd/Makefile | 2 + httpd/axhttp.h | 2 +- httpd/main.c | 34 ++- httpd/mime_types.c | 6 +- httpd/proc.c | 62 +++--- samples/c/axssl.c | 10 +- samples/csharp/axssl.cs | 17 +- samples/java/axssl.java | 26 +-- samples/perl/axssl.pl | 8 +- samples/vbnet/axssl.vb | 11 +- ssl/Config.in | 13 ++ ssl/Makefile | 4 +- ssl/aes.c | 1 - ssl/bigint.c | 10 +- ssl/bigint.h | 10 +- ssl/crypto.h | 21 +- ssl/crypto_misc.c | 41 ---- ssl/loader.c | 28 +-- ssl/md5.c | 5 +- ssl/p12.c | 1 + ssl/rc4.c | 4 - ssl/rsa.c | 19 +- ssl/sha1.c | 6 +- ssl/ssl.h | 19 +- ssl/test/ssltest.c | 330 ++++++++++++++++++---------- ssl/tls1.c | 232 ++++++++++--------- ssl/tls1.h | 41 +++- ssl/tls1_clnt.c | 33 +-- ssl/tls1_svr.c | 29 ++- 40 files changed, 611 insertions(+), 545 deletions(-) diff --git a/Makefile b/Makefile index 03a220e5f..33c1debe4 100644 --- a/Makefile +++ b/Makefile @@ -44,9 +44,13 @@ ifdef CONFIG_SAMPLES $(MAKE) -C samples endif -$(STAGE) : +$(STAGE) : ssl/version.h @mkdir -p $(STAGE) +# create a version file with something in it. +ssl/version.h: + @echo "#define AXTLS_VERSION \"(no version)\"" > ssl/version.h + $(PREFIX) : @mkdir -p $(PREFIX)/lib @mkdir -p $(PREFIX)/bin @@ -56,6 +60,7 @@ release: -$(MAKE) clean -@rm config/*.msi config/*.back.aip config/config.h config/.config* @rm -fr $(STAGE) + @echo "#define AXTLS_VERSION \"$(VERSION)\"" > ssl/version.h cd ../; tar cvfz $(RELEASE).tar.gz --wildcards-match-slash --exclude .svn axTLS; cd -; docs: diff --git a/README b/README index db35888d7..fcc18121b 100644 --- a/README +++ b/README @@ -115,7 +115,7 @@ ActiveState's version works ok). communicate securely because they have no common encryption algorithms" (v1.5), or "Firefox can't connect to because the site uses a security protocol which isn't enabled" (v2.0). See bugzilla issues - 343543 and 359484 (Comment #7). It's all broken (hopefully fixed soon). + 343543 and 359484 (Comment #7). It's all broken (hopefully fixed soon). * Perl/Java bindings don't work on 64 bit Linux machines. I can't even compile the latest version of Perl on an AMD64 box (using FC3). @@ -148,7 +148,7 @@ Solaris issues ============== * mconf doesn't work well - some manual tweaking is required for string values. -* GNU make and GNU patch are required and need to be in $PATH. +* GNU make is required and needs to be in $PATH. * To get swig's library dependencies to work (and for the C library to be found), I needed to type: diff --git a/bindings/csharp/axTLS.cs b/bindings/csharp/axTLS.cs index 9362fbae2..a59209168 100644 --- a/bindings/csharp/axTLS.cs +++ b/bindings/csharp/axTLS.cs @@ -185,6 +185,14 @@ namespace axTLS { axtls.ssl_display_error(error_code); } + + /** + * @brief Return the version of the axTLS project. + */ + public static string Version() + { + return axtls.ssl_version(); + } } /** diff --git a/bindings/generate_SWIG_interface.pl b/bindings/generate_SWIG_interface.pl index dea277e6e..3732a1d38 100755 --- a/bindings/generate_SWIG_interface.pl +++ b/bindings/generate_SWIG_interface.pl @@ -30,6 +30,7 @@ sub transformSignature # make API Java more 'byte' friendly $line =~ s/uint32_t/int/g; $line =~ s/const uint8_t \* /const unsigned char \* /g; + $line =~ s/\(void\)/()/g; if ($ARGV[0] eq "-java") { $line =~ s/.*ssl_read.*//g; diff --git a/bindings/generate_interface.pl b/bindings/generate_interface.pl index fee6eb4c5..193b5adf4 100755 --- a/bindings/generate_interface.pl +++ b/bindings/generate_interface.pl @@ -59,6 +59,7 @@ sub transformSignature $line =~ s/SSLCTX \* ?/IntPtr /g; $line =~ s/SSLObjLoader \* ?/IntPtr /g; $line =~ s/SSL \* ?/IntPtr /g; + $line =~ s/\(void\)/()/g; } elsif ($binding == $VBNET) { diff --git a/bindings/java/SSLUtil.java b/bindings/java/SSLUtil.java index d5b6ba9f2..a59de3f1f 100644 --- a/bindings/java/SSLUtil.java +++ b/bindings/java/SSLUtil.java @@ -92,5 +92,13 @@ public class SSLUtil { axtlsj.ssl_display_error(error_code); } + + /** + * @brief Return the version of the axTLS project. + */ + public static String version() + { + return axtlsj.ssl_version(); + } } diff --git a/bindings/vbnet/axTLSvb.vb b/bindings/vbnet/axTLSvb.vb index c07258df4..9cec32c78 100644 --- a/bindings/vbnet/axTLSvb.vb +++ b/bindings/vbnet/axTLSvb.vb @@ -83,6 +83,10 @@ Namespace axTLSvb Public Shared Sub DisplayError(ByVal error_code As Integer) axtls.ssl_display_error(error_code) End Sub + + Public Shared Function Version() As String + Return axtls.ssl_version() + End Function End Class Public Class SSLCTX diff --git a/config/axhttpd.aip b/config/axhttpd.aip index a1806c0c0..25e067abe 100755 --- a/config/axhttpd.aip +++ b/config/axhttpd.aip @@ -1,17 +1,17 @@ - + - + - + - - + + @@ -23,16 +23,6 @@ - - - - - - - - - - @@ -46,24 +36,14 @@ - - - - - - - - - - + - @@ -76,58 +56,18 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - - - - - + @@ -163,10 +103,6 @@ - - - - diff --git a/config/linuxconfig b/config/linuxconfig index 757d0f75c..1fd7cfa47 100644 --- a/config/linuxconfig +++ b/config/linuxconfig @@ -39,6 +39,7 @@ CONFIG_SSL_USE_PKCS12=y CONFIG_SSL_EXPIRY_TIME=24 CONFIG_X509_MAX_CA_CERTS=4 CONFIG_SSL_MAX_CERTS=2 +# CONFIG_SSL_CTX_MUTEXING is not set CONFIG_USE_DEV_URANDOM=y # CONFIG_WIN32_USE_CRYPTO_LIB is not set # CONFIG_PERFORMANCE_TESTING is not set diff --git a/config/win32config b/config/win32config index a275fd2fb..54a694543 100644 --- a/config/win32config +++ b/config/win32config @@ -43,6 +43,7 @@ CONFIG_SSL_USE_PKCS12=y CONFIG_SSL_EXPIRY_TIME=24 CONFIG_X509_MAX_CA_CERTS=4 CONFIG_SSL_MAX_CERTS=2 +# CONFIG_SSL_CTX_MUTEXING is not set # CONFIG_USE_DEV_URANDOM is not set CONFIG_WIN32_USE_CRYPTO_LIB=y # CONFIG_PERFORMANCE_TESTING is not set diff --git a/docsrc/doco_footer.html b/docsrc/doco_footer.html index e16051cba..20c4e70b7 100644 --- a/docsrc/doco_footer.html +++ b/docsrc/doco_footer.html @@ -1,3 +1,3 @@

-Copyright © 2006 Cameron Rich +Copyright © 2007 Cameron Rich diff --git a/httpd/Makefile b/httpd/Makefile index 6e6df2155..442dca403 100644 --- a/httpd/Makefile +++ b/httpd/Makefile @@ -58,6 +58,8 @@ OBJ= \ proc.o \ mime_types.o +include ../config/makefile.post + ifndef CONFIG_PLATFORM_WIN32 $(TARGET): $(OBJ) ../$(STAGE)/libaxtls.a diff --git a/httpd/axhttp.h b/httpd/axhttp.h index 9099317df..dde47e60d 100644 --- a/httpd/axhttp.h +++ b/httpd/axhttp.h @@ -32,7 +32,7 @@ #define BLOCKSIZE 4096 #define INITIAL_CONNECTION_SLOTS 10 -#define CONFIG_HTTP_DEFAULT_SSL_OPTIONS 0 +#define CONFIG_HTTP_DEFAULT_SSL_OPTIONS 0 #define STATE_WANT_TO_READ_HEAD 1 #define STATE_WANT_TO_SEND_HEAD 2 diff --git a/httpd/main.c b/httpd/main.c index 8de750f45..dd0e09fdf 100644 --- a/httpd/main.c +++ b/httpd/main.c @@ -24,7 +24,6 @@ #include #include "axhttp.h" -// GLOBALS struct serverstruct *servers; struct connstruct *usedconns; struct connstruct *freeconns; @@ -99,7 +98,7 @@ int main(int argc, char *argv[]) WSADATA wsaData; WSAStartup(wVersionRequested,&wsaData); #else - if (getuid() == 0) // change our uid if we are root + if (getuid() == 0) /* change our uid if we are root */ { setgid(32767); setuid(32767); @@ -111,6 +110,7 @@ int main(int argc, char *argv[]) signal(SIGCHLD, reaper); #endif #endif + signal(SIGINT, sigint_cleanup); signal(SIGTERM, die); mime_init(); @@ -167,8 +167,8 @@ int main(int argc, char *argv[]) addcgiext(CONFIG_HTTP_CGI_EXTENSION); #endif #if defined(CONFIG_HTTP_VERBOSE) - printf("axhttpd: listening on ports http:%d and https:%d\n", - CONFIG_HTTP_PORT, CONFIG_HTTP_HTTPS_PORT); + printf("axhttpd (%s): listening on ports %d (http) and %d (https)\n", + ssl_version(), CONFIG_HTTP_PORT, CONFIG_HTTP_HTTPS_PORT); TTY_FLUSH(); #endif #if defined(CONFIG_HTTP_IS_DAEMON) @@ -178,7 +178,7 @@ int main(int argc, char *argv[]) setsid(); #endif - // main loop + /* main loop */ while (1) { FD_ZERO(&rfds); @@ -186,7 +186,7 @@ int main(int argc, char *argv[]) rnum = wnum = -1; sp = servers; - while (sp != NULL) // read each server port + while (sp != NULL) /* read each server port */ { FD_SET(sp->sd, &rfds); @@ -195,13 +195,13 @@ int main(int argc, char *argv[]) sp = sp->next; } - // Add the established sockets + /* Add the established sockets */ tp = usedconns; currtime = time(NULL); while (tp != NULL) { - if (currtime > tp->timeout) // timed out? Kill it. + if (currtime > tp->timeout) /* timed out? Kill it. */ { to = tp; tp = tp->next; @@ -253,7 +253,7 @@ int main(int argc, char *argv[]) wnum != -1 ? &wfds : NULL, NULL, NULL); - // New connection? + /* New connection? */ sp = servers; while (active > 0 && sp != NULL) { @@ -266,7 +266,7 @@ int main(int argc, char *argv[]) sp = sp->next; } - // Handle the established sockets + /* Handle the established sockets */ tp = usedconns; while (active > 0 && tp != NULL) @@ -446,14 +446,10 @@ static void handlenewconnection(int listenfd, int is_ssl) int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp); if (tp == sizeof(struct sockaddr_in6)) - { inet_ntop(AF_INET6, &their_addr.sin6_addr, ipbuf, sizeof(ipbuf)); - } else if (tp == sizeof(struct sockaddr_in)) - { inet_ntop(AF_INET, &(((struct sockaddr_in *)&their_addr)->sin_addr), ipbuf, sizeof(ipbuf)); - } else *ipbuf = '\0'; @@ -539,7 +535,7 @@ static void addconnection(int sd, char *ip, int is_ssl) { struct connstruct *tp; - // Get ourselves a connstruct + /* Get ourselves a connstruct */ if (freeconns == NULL) tp = (struct connstruct *)malloc(sizeof(struct connstruct)); else @@ -548,7 +544,7 @@ static void addconnection(int sd, char *ip, int is_ssl) freeconns = tp->next; } - // Attach it to the used list + /* Attach it to the used list */ tp->next = usedconns; usedconns = tp; tp->networkdesc = sd; @@ -605,11 +601,11 @@ void removeconnection(struct connstruct *cn) if (shouldret) return; - // If we did, add it to the free list + /* If we did, add it to the free list */ cn->next = freeconns; freeconns = cn; - // Close it all down + /* Close it all down */ if (cn->networkdesc != -1) { if (cn->is_ssl) @@ -626,7 +622,7 @@ void removeconnection(struct connstruct *cn) #ifdef WIN32 FindClose(cn->dirp); #else - closedir(cn->dirp); + closedir(cn->dirp); #endif #endif } diff --git a/httpd/mime_types.c b/httpd/mime_types.c index d4c88da9a..1335e7d0d 100644 --- a/httpd/mime_types.c +++ b/httpd/mime_types.c @@ -32,18 +32,18 @@ typedef struct static mime_table_t mime_table[] = { - // Fundamentals + /* Fundamental types */ { ".html", "text/html" }, { ".htm", "text/html" }, { ".css", "text/css" }, - // Basic graphics + /* Basic graphics */ { ".jpg", "image/jpeg" }, { ".gif", "image/gif" }, { ".png", "image/png" }, #ifdef CONFIG_HTTP_ALL_MIME_TYPES - // This list is a bit expensive to maintain normally, so it's an option. + /* This list is a bit expensive to maintain normally, so it's an option. */ { ".txt", "text/plain" }, { ".rtx", "text/richtext" }, { ".etx", "text/x-setext" }, diff --git a/httpd/proc.c b/httpd/proc.c index 2b5890296..9a59908d3 100644 --- a/httpd/proc.c +++ b/httpd/proc.c @@ -48,7 +48,7 @@ static void split(char *tp, char *sp[], int maxwords, char sc); static int iscgi(const char *fn); #endif -// Returns 1 if elems should continue being read, 0 otherwise +/* Returns 1 if elems should continue being read, 0 otherwise */ static int procheadelem(struct connstruct *cn, char *buf) { char *delim, *value; @@ -79,8 +79,6 @@ static int procheadelem(struct connstruct *cn, char *buf) if (sanitizefile(value) == 0) { -printf("#3\n"); -TTY_FLUSH(); send404(cn); removeconnection(cn); return 0; @@ -155,7 +153,7 @@ static void procdirlisting(struct connstruct *cn) return; } - // Get rid of the "." + /* Get rid of the "." */ readdir(cn->dirp); #endif @@ -198,12 +196,12 @@ void procdodir(struct connstruct *cn) file = dp->d_name; #endif - // if no index file, don't display the ".." directory + /* if no index file, don't display the ".." directory */ if (cn->filereq[0] == '/' && cn->filereq[1] == '\0' && strcmp(file, "..") == 0) continue; - // don't display files beginning with "." + /* don't display files beginning with "." */ if (file[0] == '.' && file[1] != '.') continue; @@ -257,7 +255,7 @@ void procreadhead(struct connstruct *cn) rv = special_read(cn, buf, sizeof(buf)-1); if (rv <= 0) { - if (rv < 0) // really dead? + if (rv < 0) /* really dead? */ removeconnection(cn); return; } @@ -265,10 +263,10 @@ void procreadhead(struct connstruct *cn) buf[rv] = '\0'; next = tp = buf; - // Split up lines and send to procheadelem() + /* Split up lines and send to procheadelem() */ while (*next != '\0') { - // If we have a blank line, advance to next stage! + /* If we have a blank line, advance to next stage! */ if (*next == '\r' || *next == '\n') { buildactualfile(cn); @@ -319,7 +317,7 @@ void procsendhead(struct connstruct *cn) #if defined(CONFIG_HTTP_HAS_CGI) if (trycgi_withpathinfo(cn) == 0) { - // We Try To Find A CGI + /* We Try To Find A CGI */ proccgi(cn, 1); return; } @@ -334,7 +332,7 @@ void procsendhead(struct connstruct *cn) if (iscgi(cn->actualfile)) { #ifndef WIN32 - // Set up CGI script + /* Set up CGI script */ if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) { send404(cn); @@ -350,11 +348,11 @@ void procsendhead(struct connstruct *cn) if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { - // Check to see if this dir has an index file + /* Check to see if this dir has an index file */ if (procindex(cn, &stbuf) == 0) { #if defined(CONFIG_HTTP_DIRECTORIES) - // If not, we do a directory listing of it + /* If not, we do a directory listing of it */ procdirlisting(cn); #else send404(cn); @@ -364,10 +362,10 @@ void procsendhead(struct connstruct *cn) } #if defined(CONFIG_HTTP_HAS_CGI) - // If the index is a CGI file, handle it like any other CGI + /* If the index is a CGI file, handle it like any other CGI */ if (iscgi(cn->actualfile)) { - // Set up CGI script + /* Set up CGI script */ if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) { send404(cn); @@ -383,7 +381,7 @@ void procsendhead(struct connstruct *cn) if (cn->modified_since) { - // file has already been read before + /* file has already been read before */ snprintf(buf, sizeof(buf), "HTTP/1.1 304 Not Modified\nServer: " "axhttpd V%s\nDate: %s\n", VERSION, date); special_write(cn, buf, strlen(buf)); @@ -402,7 +400,7 @@ void procsendhead(struct connstruct *cn) "Content-Type: %s\nContent-Length: %ld\n" "Date: %sLast-Modified: %s\n", VERSION, getmimetype(cn->actualfile), (long) stbuf.st_size, - date, ctime(&(stbuf.st_mtime))); // ctime() has a \n on the end + date, ctime(&(stbuf.st_mtime))); /* ctime() has a \n on the end */ special_write(cn, buf, strlen(buf)); @@ -505,8 +503,8 @@ static int special_read(struct connstruct *cn, void *buf, size_t count) if (cn->is_ssl) { - SSL *ssl = ssl_find(servers->ssl_ctx, cn->networkdesc); uint8_t *read_buf; + SSL *ssl = ssl_find(servers->ssl_ctx, cn->networkdesc); if ((res = ssl_read(ssl, &read_buf)) > SSL_OK) memcpy(buf, read_buf, res > (int)count ? count : res); @@ -517,9 +515,9 @@ static int special_read(struct connstruct *cn, void *buf, size_t count) return res; } -// Returns 0 if no index was found and doesn't modify cn->actualfile -// Returns 1 if an index was found and puts the index in cn->actualfile -// and puts its stat info into stp +/* Returns 0 if no index was found and doesn't modify cn->actualfile + Returns 1 if an index was found and puts the index in cn->actualfile + and puts its stat info into stp */ static int procindex(struct connstruct *cn, struct stat *stp) { char tbuf[MAXREQUESTLENGTH]; @@ -557,9 +555,9 @@ static void proccgi(struct connstruct *cn, int has_pathinfo) #ifndef WIN32 pipe(tpipe); - if (fork() > 0) // parent + if (fork() > 0) /* parent */ { - // Close the write descriptor + /* Close the write descriptor */ close(tpipe[1]); cn->filedesc = tpipe[0]; cn->state = STATE_WANT_TO_READ_FILE; @@ -567,16 +565,16 @@ static void proccgi(struct connstruct *cn, int has_pathinfo) return; } - // The problem child... + /* The problem child... */ - // Our stdout/stderr goes to the socket + /* Our stdout/stderr goes to the socket */ dup2(tpipe[1], 1); dup2(tpipe[1], 2); - // If it was a POST request, send the socket data to our stdin + /* If it was a POST request, send the socket data to our stdin */ if (cn->reqtype == TYPE_POST) dup2(cn->networkdesc, 0); - else // Otherwise we can shutdown the read side of the sock + else /* Otherwise we can shutdown the read side of the sock */ shutdown(cn->networkdesc, 0); close(tpipe[0]); @@ -645,7 +643,7 @@ static int trycgi_withpathinfo(struct connstruct *cn) { char tpfile[MAXREQUESTLENGTH]; char fr_str[MAXREQUESTLENGTH]; - char *fr_rs[MAXCGIARGS]; // filereq splitted + char *fr_rs[MAXCGIARGS]; /* filereq splitted */ int i = 0, offset; my_strncpy(fr_str, cn->filereq, MAXREQUESTLENGTH); @@ -818,14 +816,14 @@ static int sanitizefile(const char *buf) { int len, i; - // Don't accept anything not starting with a / + /* Don't accept anything not starting with a / */ if (*buf != '/') return 0; len = strlen(buf); for (i = 0; i < len; i++) { - // Check for "/." : In other words, don't send files starting with a . + /* Check for "/." i.e. don't send files starting with a . */ if (buf[i] == '/' && buf[i+1] == '.') return 0; } @@ -837,14 +835,14 @@ static int sanitizehost(char *buf) { while (*buf != '\0') { - // Handle the port + /* Handle the port */ if (*buf == ':') { *buf = '\0'; return 1; } - // Enforce some basic URL rules... + /* Enforce some basic URL rules... */ if ((isalnum(*buf) == 0 && *buf != '-' && *buf != '.') || (*buf == '.' && *(buf+1) == '.') || (*buf == '.' && *(buf+1) == '-') || diff --git a/samples/c/axssl.c b/samples/c/axssl.c index 7575c263b..7a4e1dd18 100644 --- a/samples/c/axssl.c +++ b/samples/c/axssl.c @@ -63,11 +63,15 @@ int main(int argc, char *argv[]) signal(SIGPIPE, SIG_IGN); /* ignore pipe errors */ #endif + if (argc == 2 && strcmp(argv[1], "version") == 0) + { + printf("axssl %s\n", ssl_version()); + exit(0); + } + if (argc < 2 || ( strcmp(argv[1], "s_server") && strcmp(argv[1], "s_client"))) - { print_options(argc > 1 ? argv[1] : ""); - } strcmp(argv[1], "s_server") ? do_client(argc, argv) : do_server(argc, argv); @@ -733,7 +737,7 @@ static void do_client(int argc, char *argv[]) static void print_options(char *option) { printf("axssl: Error: '%s' is an invalid command.\n", option); - printf("usage: axssl [s_server|s_client] [args ...]\n"); + printf("usage: axssl [s_server|s_client|version] [args ...]\n"); exit(1); } diff --git a/samples/csharp/axssl.cs b/samples/csharp/axssl.cs index eb8014653..1f1f95b58 100644 --- a/samples/csharp/axssl.cs +++ b/samples/csharp/axssl.cs @@ -39,28 +39,28 @@ using axTLS; public class axssl { - /* + /* * Main() */ public static void Main(string[] args) { + if (args.Length == 1 && args[0] == "version") + { + Console.WriteLine("axssl.csharp " + SSLUtil.Version()); + Environment.Exit(0); + } + axssl runner = new axssl(); if (args.Length < 1 || (args[0] != "s_server" && args[0] != "s_client")) - { runner.print_options(args.Length > 0 ? args[0] : ""); - } int build_mode = SSLUtil.BuildMode(); if (args[0] == "s_server") - { runner.do_server(build_mode, args); - } else - { runner.do_client(build_mode, args); - } } /* @@ -603,7 +603,8 @@ public class axssl { Console.WriteLine("axssl: Error: '" + option + "' is an invalid command."); - Console.WriteLine("usage: axssl.cs.exe [s_server|s_client] [args ...]"); + Console.WriteLine("usage: axssl.csharp [s_server|" + + "s_client|version] [args ...]"); Environment.Exit(1); } diff --git a/samples/java/axssl.java b/samples/java/axssl.java index 3d138c6cf..a08e9a79d 100644 --- a/samples/java/axssl.java +++ b/samples/java/axssl.java @@ -43,6 +43,12 @@ public class axssl */ public static void main(String[] args) { + if (args.length == 1 && args[0].equals("version")) + { + System.out.println("axtls.jar " + SSLUtil.version()); + System.exit(0); + } + axssl runner = new axssl(); try @@ -57,13 +63,9 @@ public class axssl int build_mode = SSLUtil.buildMode(); if (args[0].equals("s_server")) - { runner.do_server(build_mode, args); - } else - { runner.do_client(build_mode, args); - } } catch (Exception e) { @@ -193,9 +195,7 @@ public class axssl axtlsj.SSL_DEFAULT_SVR_SESS); if (ssl_ctx == null) - { throw new Exception("Error: Server context is invalid"); - } if (private_key_file != null) { @@ -316,9 +316,7 @@ public class axssl throws Exception { if (build_mode < axtlsj.SSL_BUILD_ENABLE_CLIENT) - { print_client_options(build_mode, args[1]); - } int i = 1, res; int port = 4433; @@ -599,7 +597,7 @@ public class axssl { System.out.println("axssl: Error: '" + option + "' is an invalid command."); - System.out.println("usage: axtlsj.jar [s_server|s_client] " + + System.out.println("usage: axtlsj.jar [s_server|s_client|version] " + "[args ...]"); System.exit(1); } @@ -701,25 +699,15 @@ public class axssl byte ciph_id = ssl.getCipherId(); if (ciph_id == axtlsj.SSL_AES128_SHA) - { System.out.println("AES128-SHA"); - } else if (ciph_id == axtlsj.SSL_AES256_SHA) - { System.out.println("AES256-SHA"); - } else if (ciph_id == axtlsj.SSL_RC4_128_SHA) - { System.out.println("RC4-SHA"); - } else if (ciph_id == axtlsj.SSL_RC4_128_MD5) - { System.out.println("RC4-MD5"); - } else - { System.out.println("Unknown - " + ssl.getCipherId()); - } } public char toHexChar(int i) diff --git a/samples/perl/axssl.pl b/samples/perl/axssl.pl index e0200ea0b..cbfd58fdb 100755 --- a/samples/perl/axssl.pl +++ b/samples/perl/axssl.pl @@ -62,6 +62,12 @@ sub get_native_sock # Main entry point. Doesn't do much except works out whether we are a client # or a server. # +if ($#ARGV == 0 && $ARGV[0] eq "version") +{ + printf("axssl.pl ".axtlsp::ssl_version()."\n"); + exit 0; +} + print_options($#ARGV > -1 ? $ARGV[0] : "") if ($#ARGV < 0 || ($ARGV[0] ne "s_server" && $ARGV[0] ne "s_client")); @@ -87,7 +93,7 @@ sub do_server my $private_key_file = undef; my $cert_size = axtlsp::ssl_get_config($axtlsp::SSL_MAX_CERT_CFG_OFFSET); my $ca_cert_size = axtlsp::ssl_get_config( - $axtlsp::SSL_MAX_CA_CERT_CFG_OFFSET); + $axtlsp::SSL_MAX_CA_CERT_CFG_OFFSET); my @cert; my @ca_cert; diff --git a/samples/vbnet/axssl.vb b/samples/vbnet/axssl.vb index ce64db5e8..da6f71984 100644 --- a/samples/vbnet/axssl.vb +++ b/samples/vbnet/axssl.vb @@ -98,7 +98,8 @@ Public Class axssl If args(i) = "-verify" Then options = options Or axtls.SSL_CLIENT_AUTHENTICATION ElseIf args(i) = "-CAfile" - If i >= args.Length-1 Or ca_cert_index >= ca_cert_size Then + If i >= args.Length-1 Or _ + ca_cert_index >= ca_cert_size Then print_server_options(build_mode, args(i)) End If @@ -553,7 +554,8 @@ Public Class axssl Public Sub print_options(ByVal options As String) Console.WriteLine("axssl: Error: '" & options & _ "' is an invalid command.") - Console.WriteLine("usage: axssl.vb.exe [s_server|s_client] [args ...]") + Console.WriteLine("usage: axssl.vbnet [s_server|s_client|" & _ + "version] [args ...]") Environment.Exit(1) End Sub @@ -663,6 +665,11 @@ Public Module MyMain Function Main(ByVal args() As String) As Integer Dim runner As axssl = New axssl() + If args.Length = 1 And args(0) = "version" Then + Console.WriteLine("axssl.vbnet " & SSLUtil.Version()) + Environment.Exit(0) + End If + If args.Length < 1 runner.print_options("") ElseIf args(0) <> "s_server" And args(0) <> "s_client" diff --git a/ssl/Config.in b/ssl/Config.in index 56c7173ef..76b7f49c0 100644 --- a/ssl/Config.in +++ b/ssl/Config.in @@ -210,6 +210,19 @@ config CONFIG_SSL_MAX_CERTS The default is to allow one certificate + 1 certificate in the chain (which may be the certificate authority certificate). +config CONFIG_SSLCTX_MUTEXING + bool "Enable SSLCTX mutexing" + default n + help + Normally mutexing is not required - each SSLCTX object can deal with + many SSL objects (as long as each SSLCTX object is using a single + thread). + + If the SSLCTX object is not thread safe e.g. the case where a + new thread is created for each SSL object, then mutexing is required. + + Select y when a mutex on the SSLCTX object is required. + config CONFIG_USE_DEV_URANDOM bool "Use /dev/urandom" default y diff --git a/ssl/Makefile b/ssl/Makefile index 7137fb7e0..69392b591 100644 --- a/ssl/Makefile +++ b/ssl/Makefile @@ -39,7 +39,7 @@ endif # shared library major/minor numbers LIBMAJOR=$(BASETARGET).1 -LIBMINOR=$(BASETARGET).1.0 +LIBMINOR=$(BASETARGET).1.1 else TARGET1=axtls.lib TARGET2=../$(STAGE)/axtls.dll @@ -49,7 +49,7 @@ endif libs: $(TARGET1) $(TARGET2) OBJ=\ - aes.o \ + aes.o \ asn1.o \ bigint.o \ crypto_misc.o \ diff --git a/ssl/aes.c b/ssl/aes.c index 9154a5153..20922a46c 100644 --- a/ssl/aes.c +++ b/ssl/aes.c @@ -400,7 +400,6 @@ static void AES_encrypt(const AES_CTX *ctx, uint32_t *data) a1 ^= tmp1 ^ AES_xtime(a1 ^ a2); a2 ^= tmp1 ^ AES_xtime(a2 ^ a3); a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0); - } tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3); diff --git a/ssl/bigint.c b/ssl/bigint.c index e0427a6e5..56c94e37b 100644 --- a/ssl/bigint.c +++ b/ssl/bigint.c @@ -781,7 +781,9 @@ void bi_free_mod(BI_CTX *ctx, int mod_offset) */ static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) { - int i, j, i_plus_j, n = bia->size, t = bib->size; + int i, j, i_plus_j; + int n = bia->size; + int t = bib->size; bigint *biR = alloc(ctx, n + t); comp *sr = biR->comps; comp *sa = bia->comps; @@ -1397,9 +1399,7 @@ bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) #ifdef CONFIG_BIGINT_SLIDING_WINDOW for (j = i; j > 32; j /= 5) /* work out an optimum size */ - { window_size++; - } /* work out the slide constants */ precompute_slide_window(ctx, window_size, bi); @@ -1420,15 +1420,11 @@ bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) int part_exp = 0; if (l < 0) /* LSB of exponent will always be 1 */ - { l = 0; - } else { while (exp_bit_is_one(biexp, l) == 0) - { l++; /* go back up */ - } } /* build up the section of the exponent */ diff --git a/ssl/bigint.h b/ssl/bigint.h index e233d7980..5a13c5ae4 100644 --- a/ssl/bigint.h +++ b/ssl/bigint.h @@ -74,14 +74,14 @@ bigint *bi_str_import(BI_CTX *ctx, const char *data); * appropriate reduction technique (which is bi_mod() when doing classical * reduction). */ -#if defined(CONFIG_BIGINT_CLASSICAL) -#define bi_residue(A, B) bi_mod(A, B) +#if defined(CONFIG_BIGINT_MONTGOMERY) +#define bi_residue(A, B) bi_mont(A, B) +bigint *bi_mont(BI_CTX *ctx, bigint *bixy); #elif defined(CONFIG_BIGINT_BARRETT) #define bi_residue(A, B) bi_barrett(A, B) bigint *bi_barrett(BI_CTX *ctx, bigint *bi); -#else /* CONFIG_BIGINT_MONTGOMERY */ -#define bi_residue(A, B) bi_mont(A, B) -bigint *bi_mont(BI_CTX *ctx, bigint *bixy); +#else /* if defined(CONFIG_BIGINT_CLASSICAL) */ +#define bi_residue(A, B) bi_mod(A, B) #endif #ifdef CONFIG_BIGINT_SQUARE diff --git a/ssl/crypto.h b/ssl/crypto.h index f6277adcc..ab43972a5 100644 --- a/ssl/crypto.h +++ b/ssl/crypto.h @@ -143,7 +143,6 @@ typedef struct bigint *qInv; /* q^-1 mod p */ #endif int num_octets; - bigint *sig_m; /* signature modulus */ BI_CTX *bi_ctx; } RSA_CTX; @@ -163,15 +162,14 @@ void RSA_pub_key_new(RSA_CTX **rsa_ctx, const uint8_t *modulus, int mod_len, const uint8_t *pub_exp, int pub_len); void RSA_free(RSA_CTX *ctx); -int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, +int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, int is_decryption); -bigint *RSA_private(RSA_CTX *c, bigint *bi_msg); +bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg); #ifdef CONFIG_SSL_CERT_VERIFICATION -bigint *RSA_raw_sign_verify(RSA_CTX *c, bigint *bi_msg); bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, bigint *modulus, bigint *pub_exp); -bigint *RSA_public(RSA_CTX *c, bigint *bi_msg); -int RSA_encrypt(RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, +bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg); +int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, uint8_t *out_data, int is_signing); void RSA_print(const RSA_CTX *ctx); #endif @@ -267,17 +265,6 @@ typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int); typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key, int key_len, uint8_t *digest); -typedef struct -{ - uint8_t *pre_data; /* include the ssl record bytes */ - uint8_t *data; /* the regular ssl data */ - int max_len; - int index; -} BUF_MEM; - -BUF_MEM buf_new(void); -void buf_grow(BUF_MEM *bm, int len); -void buf_free(BUF_MEM *bm); int get_file(const char *filename, uint8_t **buf); #if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG) diff --git a/ssl/crypto_misc.c b/ssl/crypto_misc.c index a818c5f4b..030ed650c 100644 --- a/ssl/crypto_misc.c +++ b/ssl/crypto_misc.c @@ -29,8 +29,6 @@ #include "wincrypt.h" #endif -#define BM_RECORD_OFFSET 5 /* same as SSL_RECORD_SIZE */ - #ifndef WIN32 static int rng_fd = -1; #elif defined(CONFIG_WIN32_USE_CRYPTO_LIB) @@ -44,45 +42,6 @@ static uint64_t rng_num; static int rng_ref_count; const char * const unsupported_str = "Error: feature not supported\n"; -/** - * Allocate a new memory buffer - */ -BUF_MEM buf_new() -{ - BUF_MEM bm; - bm.pre_data = (uint8_t *)calloc(1, 2048); /* start with this */ - bm.data = bm.pre_data+BM_RECORD_OFFSET; /* some space at the start */ - bm.max_len = 2048-BM_RECORD_OFFSET; - bm.index = 0; - return bm; -} - -/** - * Grow a buffer if necessary - */ -void buf_grow(BUF_MEM *bm, int len) -{ - if (len <= bm->max_len) - { - return; - } - - /* add 1kB just to be sure */ - bm->pre_data = (uint8_t *)realloc(bm->pre_data, len+1024+BM_RECORD_OFFSET); - bm->data = bm->pre_data+BM_RECORD_OFFSET; - bm->max_len = len + 1024; -} - -/** - * Free a buffer - */ -void buf_free(BUF_MEM *bm) -{ - free(bm->pre_data); - bm->pre_data = NULL; - bm->data = NULL; -} - #ifndef CONFIG_SSL_SKELETON_MODE /** * Retrieve a file and put it into memory diff --git a/ssl/loader.c b/ssl/loader.c index c8b74f3b2..1bc966515 100644 --- a/ssl/loader.c +++ b/ssl/loader.c @@ -76,9 +76,7 @@ EXP_FUNC int STDCALL ssl_obj_load(SSLCTX *ssl_ctx, int obj_type, #endif } else - { ret = do_obj(ssl_ctx, obj_type, ssl_obj, password); - } error: ssl_obj_free(ssl_obj); @@ -149,15 +147,18 @@ static int do_obj(SSLCTX *ssl_ctx, int obj_type, } /* - * Release things. + * Clean up our mess. */ void ssl_obj_free(SSLObjLoader *ssl_obj) { - free(ssl_obj->buf); - free(ssl_obj); + if (ssl_obj) + { + free(ssl_obj->buf); + free(ssl_obj); + } } -/** +/* * Support for PEM encoded keys/certificates. */ #ifdef CONFIG_SSL_HAS_PEM @@ -214,7 +215,7 @@ static int base64_decode(const uint8_t *in, int len, g = 3; for (x = y = z = t = 0; x < len; x++) { - if ((c = map[in[x]&0x7F]) == 0xff) + if ((c = map[in[x] & 0x7F]) == 0xff) continue; if (c == 254) /* this is the end... */ @@ -234,14 +235,10 @@ static int base64_decode(const uint8_t *in, int len, out[z++] = (uint8_t)((t>>16)&255); if (g > 1) - { out[z++] = (uint8_t)((t>>8)&255); - } if (g > 2) - { out[z++] = (uint8_t)(t&255); - } y = t = 0; } @@ -256,9 +253,7 @@ static int base64_decode(const uint8_t *in, int len, error: #ifdef CONFIG_SSL_FULL_MODE if (ret < 0) - { printf("Error: Invalid base64 file\n"); - } #endif return ret; } @@ -312,7 +307,7 @@ static int pem_decrypt(const uint8_t *where, const uint8_t *end, uint8_t c = *start++ - '0'; iv[i] = (c > 9 ? c + '0' - 'A' + 10 : c) << 4; c = *start++ - '0'; - iv[i] +=(c > 9 ? c + '0' - 'A' + 10 : c); + iv[i] += (c > 9 ? c + '0' - 'A' + 10 : c); } while (*start == '\r' || *start == '\n') @@ -402,10 +397,7 @@ static int new_pem_obj(SSLCTX *ssl_ctx, int is_cacert, uint8_t *where, /* In a format we can now understand - so process it */ if ((ret = do_obj(ssl_ctx, obj_type, ssl_obj, password))) - { - ssl_obj_free(ssl_obj); goto error; - } end += strlen(ends[i]); remain -= strlen(ends[i]); @@ -415,7 +407,6 @@ static int new_pem_obj(SSLCTX *ssl_ctx, int is_cacert, uint8_t *where, remain--; } - ssl_obj_free(ssl_obj); break; } } @@ -428,6 +419,7 @@ static int new_pem_obj(SSLCTX *ssl_ctx, int is_cacert, uint8_t *where, ret = new_pem_obj(ssl_ctx, is_cacert, end, remain, password); error: + ssl_obj_free(ssl_obj); return ret; } diff --git a/ssl/md5.c b/ssl/md5.c index b069011b7..704ba05f8 100644 --- a/ssl/md5.c +++ b/ssl/md5.c @@ -47,7 +47,7 @@ static void MD5Transform(uint32_t state[4], const uint8_t block[64]); static void Encode(uint8_t *output, uint32_t *input, uint32_t len); static void Decode(uint32_t *output, const uint8_t *input, uint32_t len); -static uint8_t PADDING[64] = +static const uint8_t PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -114,8 +114,7 @@ void MD5Update(MD5_CTX *ctx, const uint8_t * msg, int len) x = (uint32_t)((ctx->count[0] >> 3) & 0x3F); /* Update number of bits */ - if ((ctx->count[0] += ((uint32_t)len << 3)) - < ((uint32_t)len << 3)) + if ((ctx->count[0] += ((uint32_t)len << 3)) < ((uint32_t)len << 3)) ctx->count[1]++; ctx->count[1] += ((uint32_t)len >> 29); diff --git a/ssl/p12.c b/ssl/p12.c index f88594f19..fe0b82c71 100644 --- a/ssl/p12.c +++ b/ssl/p12.c @@ -389,6 +389,7 @@ int pkcs12_decode(SSLCTX *ssl_ctx, SSLObjLoader *ssl_obj, const char *password) /* get the salt */ if ((len = asn1_next_obj(buf, &offset, ASN1_OCTET_STRING)) < 0 || len != 8) goto error; + salt = &buf[offset]; /* work out what the mac should be */ diff --git a/ssl/rc4.c b/ssl/rc4.c index 471e15ffc..7250a669b 100644 --- a/ssl/rc4.c +++ b/ssl/rc4.c @@ -36,9 +36,7 @@ void RC4_setup(RC4_CTX *ctx, const uint8_t *key, int length) m = ctx->m; for (i = 0; i < 256; i++) - { m[i] = i; - } for (i = 0; i < 256; i++) { @@ -48,9 +46,7 @@ void RC4_setup(RC4_CTX *ctx, const uint8_t *key, int length) m[j] = a; if (++k >= length) - { k = 0; - } } } diff --git a/ssl/rsa.c b/ssl/rsa.c index 60b36891f..ec856dfb6 100644 --- a/ssl/rsa.c +++ b/ssl/rsa.c @@ -28,7 +28,7 @@ #include "crypto.h" #ifdef CONFIG_BIGINT_CRT -static bigint *bi_crt(RSA_CTX *rsa, bigint *bi); +static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi); #endif void RSA_priv_key_new(RSA_CTX **ctx, @@ -126,8 +126,8 @@ void RSA_free(RSA_CTX *rsa_ctx) * @return The number of bytes that were originally encrypted. -1 on error. * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 */ -int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, - int is_decryption) +int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, + uint8_t *out_data, int is_decryption) { int byte_size = ctx->num_octets; uint8_t *block; @@ -155,10 +155,9 @@ int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */ { while (block[i++] == 0xff && i < byte_size); + if (block[i-2] != 0xff) - { i = byte_size; /*ensure size is 0 */ - } } else /* PKCS1.5 encryption padding is random */ #endif @@ -169,9 +168,7 @@ int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, /* get only the bit we want */ if (size > 0) - { memcpy(out_data, &block[i], size); - } free(block); return size ? size : -1; @@ -180,7 +177,7 @@ int RSA_decrypt(RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, /** * Performs m = c^d mod n */ -bigint *RSA_private(RSA_CTX *c, bigint *bi_msg) +bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg) { #ifdef CONFIG_BIGINT_CRT return bi_crt(c, bi_msg); @@ -197,7 +194,7 @@ bigint *RSA_private(RSA_CTX *c, bigint *bi_msg) * This should really be in bigint.c (and was at one stage), but needs * access to the RSA_CTX context... */ -static bigint *bi_crt(RSA_CTX *rsa, bigint *bi) +static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi) { BI_CTX *ctx = rsa->bi_ctx; bigint *m1, *m2, *h; @@ -245,7 +242,7 @@ void RSA_print(const RSA_CTX *rsa_ctx) /** * Performs c = m^e mod n */ -bigint *RSA_public(RSA_CTX *c, bigint *bi_msg) +bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg) { c->bi_ctx->mod_offset = BIGINT_M_OFFSET; return bi_mod_power(c->bi_ctx, bi_msg, c->e); @@ -255,7 +252,7 @@ bigint *RSA_public(RSA_CTX *c, bigint *bi_msg) * Use PKCS1.5 for encryption/signing. * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 */ -int RSA_encrypt(RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, +int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, uint8_t *out_data, int is_signing) { int byte_size = ctx->num_octets; diff --git a/ssl/sha1.c b/ssl/sha1.c index 9a42801f2..3feb6d54c 100644 --- a/ssl/sha1.c +++ b/ssl/sha1.c @@ -57,17 +57,13 @@ void SHA1Update(SHA1_CTX *ctx, const uint8_t *msg, int len) while (len--) { ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF); - ctx->Length_Low += 8; + if (ctx->Length_Low == 0) - { ctx->Length_High++; - } if (ctx->Message_Block_Index == 64) - { SHA1ProcessMessageBlock(ctx); - } msg++; } diff --git a/ssl/ssl.h b/ssl/ssl.h index d8ff953b1..9621ec578 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -150,14 +150,17 @@ extern "C" { * @brief Establish a new client/server context. * * This function is called before any client/server SSL connections are made. - * If multiple threads are used, then each thread will have its own SSLCTX - * context. Any number of connections may be made with a single - * context. * * Each new connection will use the this context's private key and * certificate chain. If a different certificate chain is required, then a * different context needs to be be used. * + * There are two threading models supported - a single thread with one + * SSLCTX can support any number of SSL connections - and multiple threads can + * support one SSLCTX object each (the default). But if a single SSLCTX + * object uses many SSL objects in individual threads, then the + * CONFIG_SSLCTX_MUTEXING option needs to be configured. + * * @param options [in] Any particular options. At present the options * supported are: * - SSL_SERVER_VERIFY_LATER (client only): Don't stop a handshake if the server @@ -233,6 +236,7 @@ EXP_FUNC void STDCALL ssl_free(SSL *ssl); /** * @brief Read the SSL data stream. + * The socket must be in blocking mode. * @param ssl [in] An SSL object reference. * @param in_data [out] If the read was successful, a pointer to the read * buffer will be here. Do NOT ever free this memory as this buffer is used in @@ -248,7 +252,8 @@ EXP_FUNC void STDCALL ssl_free(SSL *ssl); EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data); /** - * @brief Write to the SSL data stream. + * @brief Write to the SSL data stream. + * The socket must be in blocking mode. * @param ssl [in] An SSL obect reference. * @param out_data [in] The data to be written * @param out_len [in] The number of bytes to be written. @@ -407,6 +412,12 @@ EXP_FUNC int STDCALL ssl_obj_load(SSLCTX *ssl_ctx, int obj_type, const char *fil */ EXP_FUNC int STDCALL ssl_obj_memory_load(SSLCTX *ssl_ctx, int obj_type, const uint8_t *data, int len, const char *password); +/** + * @brief Return the axTLS library version as a string. + * @note New API function for v1.1 + */ +EXP_FUNC const char * STDCALL ssl_version(void); + /** @} */ #ifdef __cplusplus diff --git a/ssl/test/ssltest.c b/ssl/test/ssltest.c index 7bbb58e0f..557118ba4 100644 --- a/ssl/test/ssltest.c +++ b/ssl/test/ssltest.c @@ -1445,179 +1445,269 @@ cleanup: return ret; } -#if 0 +/************************************************************************** + * SSL Basic Testing (test a big packet handshake) + * + **************************************************************************/ +static uint8_t basic_buf[256*1024]; + +static void do_basic(void) +{ + int client_fd; + SSL *ssl_clnt; + SSLCTX *ssl_clnt_ctx = ssl_ctx_new( + DEFAULT_CLNT_OPTION, SSL_DEFAULT_CLNT_SESS); + usleep(200000); /* allow server to start */ + + if ((client_fd = client_socket_init(g_port)) < 0) + goto error; + + if (ssl_obj_load(ssl_clnt_ctx, SSL_OBJ_X509_CACERT, + "../ssl/test/axTLS.ca_x509.cer", NULL)) + goto error; + + ssl_clnt = ssl_client_new(ssl_clnt_ctx, client_fd, NULL); + + /* check the return status */ + if (ssl_handshake_status(ssl_clnt)) + { + printf("Client "); + ssl_display_error(ssl_handshake_status(ssl_clnt)); + goto error; + } + + ssl_write(ssl_clnt, basic_buf, sizeof(basic_buf)); + ssl_free(ssl_clnt); + +error: + ssl_ctx_free(ssl_clnt_ctx); + close(client_fd); + + /* exit this thread */ +} + +static int SSL_basic_test(void) +{ + int server_fd, client_fd, ret = 0, size = 0, offset = 0; + SSLCTX *ssl_svr_ctx = NULL; + struct sockaddr_in client_addr; + uint8_t *read_buf; + int clnt_len = sizeof(client_addr); + SSL *ssl_svr; +#ifndef WIN32 + pthread_t thread; +#endif + memset(basic_buf, 0xA5, sizeof(basic_buf)/2); + memset(&basic_buf[sizeof(basic_buf)/2], 0x5A, sizeof(basic_buf)/2); + + if ((server_fd = server_socket_init(&g_port)) < 0) + goto error; + + ssl_svr_ctx = ssl_ctx_new(DEFAULT_SVR_OPTION, SSL_DEFAULT_SVR_SESS); + +#ifndef WIN32 + pthread_create(&thread, NULL, + (void *(*)(void *))do_basic, NULL); + pthread_detach(thread); +#else + CreateThread(NULL, 1024, (LPTHREAD_START_ROUTINE)do_basic, NULL, 0, NULL); +#endif + + /* Wait for a client to connect */ + if ((client_fd = accept(server_fd, + (struct sockaddr *) &client_addr, &clnt_len)) < 0) + { + ret = SSL_ERROR_SOCK_SETUP_FAILURE; + goto error; + } + + /* we are ready to go */ + ssl_svr = ssl_server_new(ssl_svr_ctx, client_fd); + + do + { + while ((size = ssl_read(ssl_svr, &read_buf)) == SSL_OK); + + if (size < SSL_OK) /* got some alert or something nasty */ + { + printf("Server "); + ssl_display_error(size); + ret = size; + break; + } + else /* looks more promising */ + { + if (memcmp(read_buf, &basic_buf[offset], size) != 0) + { + ret = SSL_NOT_OK; + break; + } + } + + offset += size; + } while (offset < sizeof(basic_buf)); + + printf(ret == SSL_OK && offset == sizeof(basic_buf) ? + "SSL basic test passed\n" : + "SSL basic test failed\n"); + TTY_FLUSH(); + + ssl_free(ssl_svr); + close(server_fd); + close(client_fd); + +error: + ssl_ctx_free(ssl_svr_ctx); + return ret; +} + +#if !defined(WIN32) && defined(CONFIG_SSL_CTX_MUTEXING) /************************************************************************** * Multi-Threading Tests * **************************************************************************/ -#define NUM_THREADS 1 -#define NUM_THREADS_STR "1" - -static SSL *my_ssls[NUM_THREADS*3]; /* enough for all client fds */ +#define NUM_THREADS 200 typedef struct { - SSLCTX *ssl_ctx; + SSLCTX *ssl_clnt_ctx; int port; int thread_id; } multi_t; -int do_connect(multi_t *multi_data) +void do_multi_clnt(multi_t *multi_data) { int res = 1, client_fd, i; SSL *ssl = NULL; char tmp[5]; - /* make sure other threads work before this one */ - if (multi_data->thread_id == NUM_THREADS) - { - sleep(2); /* sets the maximum time this test will run */ - } - if ((client_fd = client_socket_init(multi_data->port)) < 0) goto client_test_exit; - sleep(0); - ssl = ssl_client_new(multi_data->ssl_ctx, client_fd, NULL); + sleep(1); + ssl = ssl_client_new(multi_data->ssl_clnt_ctx, client_fd, NULL); if ((res = ssl_handshake_status(ssl))) - goto client_test_exit; - - sprintf(tmp, "%d\n", multi_data->thread_id); - for (i = 0; i < 100; i++) { - ssl_write(ssl, (uint8_t *)tmp, strlen(tmp)+1); + printf("Client "); + ssl_display_error(res); + goto client_test_exit; } - res = 0; + sprintf(tmp, "%d\n", multi_data->thread_id); + for (i = 0; i < 10; i++) + ssl_write(ssl, (uint8_t *)tmp, strlen(tmp)+1); + client_test_exit: ssl_free(ssl); close(client_fd); free(multi_data); - return 0; +} + +void do_multi_svr(SSL *ssl) +{ + uint8_t *read_buf; + int *res_ptr = malloc(sizeof(int)); + int res; + + for (;;) + { + res = ssl_read(ssl, &read_buf); + + /* kill the client */ + if (res != SSL_OK) + { + if (res == SSL_ERROR_CONN_LOST) + { + close(ssl->client_fd); + ssl_free(ssl); + break; + } + else if (res > 0) + { + /* do nothing */ + } + else /* some problem */ + { + printf("Server "); + ssl_display_error(res); + goto error; + } + } + } + + res = SSL_OK; +error: + *res_ptr = res; + pthread_exit(res_ptr); } int multi_thread_test(void) { int server_fd; - SSLCTX *ssl_server_ctx = NULL; - uint8_t buf[1024]; - pthread_t threads[NUM_THREADS]; - int i, res = 1; + SSLCTX *ssl_server_ctx; + SSLCTX *ssl_clnt_ctx; + pthread_t clnt_threads[NUM_THREADS]; + pthread_t svr_threads[NUM_THREADS]; + int i, res = 0; struct sockaddr_in client_addr; int clnt_len = sizeof(client_addr); - fd_set read_set; - int max_fd; - int death_total = 0; - SSLCTX *ssl_client_ctx = ssl_ctx_new(DEFAULT_CLNT_OPTION, - SSL_DEFAULT_CLNT_SESS, NULL); printf("Do multi-threading test (takes a minute)\n"); - FD_ZERO(&read_set); + ssl_server_ctx = ssl_ctx_new(DEFAULT_SVR_OPTION, SSL_DEFAULT_SVR_SESS); + ssl_clnt_ctx = ssl_ctx_new(DEFAULT_CLNT_OPTION, SSL_DEFAULT_CLNT_SESS); + + if (ssl_obj_load(ssl_clnt_ctx, SSL_OBJ_X509_CACERT, + "../ssl/test/axTLS.ca_x509.cer", NULL)) + goto error; if ((server_fd = server_socket_init(&g_port)) < 0) goto error; - FD_SET(server_fd, &read_set); - max_fd = server_fd; - - ssl_server_ctx = ssl_ctx_new(DEFAULT_SVR_OPTION|SSL_SERVER_VERIFY_LATER, - SSL_DEFAULT_SVR_SESS, NULL); - for (i = 0; i < NUM_THREADS; i++) { multi_t *multi_data = (multi_t *)malloc(sizeof(multi_t)); - multi_data->ssl_ctx = ssl_server_ctx; + multi_data->ssl_clnt_ctx = ssl_clnt_ctx; multi_data->port = g_port; multi_data->thread_id = i+1; - if (pthread_create(&threads[i], NULL, - (void *(*)(void *))do_connect, (void *)multi_data) < 0) - goto error; + pthread_create(&clnt_threads[i], NULL, + (void *(*)(void *))do_multi_clnt, (void *)multi_data); + pthread_detach(clnt_threads[i]); } - sleep(1); - - for (;;) + for (i = 0; i < NUM_THREADS; i++) { - fd_set rdfs = read_set; - int n; + SSL *ssl_svr; + int client_fd = accept(server_fd, + (struct sockaddr *)&client_addr, &clnt_len); - if ((n = select(max_fd+1, &rdfs, NULL, NULL, 0)) > 0) - { - while (n) - { - /* check for server */ - if (FD_ISSET(server_fd, &rdfs)) - { - int client_fd = accept(server_fd, - (struct sockaddr *)&client_addr, &clnt_len); + if (client_fd < 0) + goto error; - if (client_fd < 0) - goto error; + ssl_svr = ssl_server_new(ssl_server_ctx, client_fd); - if (client_fd > max_fd) /* set max fd */ - { - max_fd = client_fd; - } - - my_ssls[client_fd] = ssl_server_new( - ssl_server_ctx, client_fd); - FD_SET(client_fd, &read_set); - - if (--n == 0) - continue; - } - - i = server_fd; - - while (++i <= max_fd && n) - { - if (FD_ISSET(i, &rdfs)) - { - SSL *ssl; - ssl = my_ssls[i]; - res = ssl_read(ssl, &read_buf); - n--; - - /* kill the client */ - if (res != SSL_OK) - { - if (res == SSL_ERROR_CONN_LOST) - { - ssl_free(ssl); - my_ssls[i] = NULL; - close(i); - FD_CLR(i, &read_set); - death_total++; - } - else if (res > 0) - { - if (strcmp(NUM_THREADS_STR "\n", - (const char *)buf) == 0) - { - sleep(1); /* allow rest of data */ - goto all_ok; - } - } - else /* some problem */ - { - printf("Got some problem %d\n", res); - goto error; - } - } /* if */ - } /* if */ - } /* for */ - } - } + pthread_create(&svr_threads[i], NULL, + (void *(*)(void *))do_multi_svr, (void *)ssl_svr); } -all_ok: - printf("Multi-thread test passed (%d)\n", death_total); - res = 0; + /* make sure we've run all of the threads */ + for (i = 0; i < NUM_THREADS; i++) + { + void *thread_res; + pthread_join(svr_threads[i], &thread_res); + if (*((int *)thread_res) != 0) + res = 1; + free(thread_res); + } + + if (res) + goto error; + + printf("Multi-thread test passed (%d)\n", NUM_THREADS); error: ssl_ctx_free(ssl_server_ctx); - ssl_ctx_free(ssl_client_ctx); + ssl_ctx_free(ssl_clnt_ctx); close(server_fd); return res; } @@ -1705,6 +1795,14 @@ int main(int argc, char *argv[]) } TTY_FLUSH(); +#if !defined(WIN32) && defined(CONFIG_SSL_CTX_MUTEXING) + if (multi_thread_test()) + goto cleanup; +#endif + + if (SSL_basic_test()) + goto cleanup; + system("sh ../ssl/test/killopenssl.sh"); if (SSL_client_tests()) diff --git a/ssl/tls1.c b/ssl/tls1.c index 3b48147f0..e2e9c41ef 100644 --- a/ssl/tls1.c +++ b/ssl/tls1.c @@ -165,6 +165,8 @@ EXP_FUNC SSLCTX *STDCALL ssl_ctx_new(uint32_t options, int num_sessions) ssl_ctx->num_sessions = num_sessions; #endif + SSL_CTX_MUTEX_INIT(ssl_ctx->mutex); + #if defined(CONFIG_SSL_USE_DEFAULT_KEY) || defined(CONFIG_SSL_SKELETON_MODE) if (~options & SSL_NO_DEFAULT_KEY) { @@ -201,7 +203,7 @@ EXP_FUNC void STDCALL ssl_ctx_free(SSLCTX *ssl_ctx) if (ssl_ctx == NULL) return; - ssl = ssl_ctx->sess_head; + ssl = ssl_ctx->head; /* clear out all the ssl entries */ while (ssl) @@ -214,9 +216,7 @@ EXP_FUNC void STDCALL ssl_ctx_free(SSLCTX *ssl_ctx) #ifndef CONFIG_SSL_SKELETON_MODE /* clear out all the sessions */ for (i = 0; i < ssl_ctx->num_sessions; i++) - { session_free(ssl_ctx->ssl_sessions, i); - } free(ssl_ctx->ssl_sessions); #endif @@ -232,6 +232,7 @@ EXP_FUNC void STDCALL ssl_ctx_free(SSLCTX *ssl_ctx) remove_ca_certs(ssl_ctx->ca_cert_ctx); #endif ssl_ctx->chain_length = 0; + SSL_CTX_MUTEX_DESTROY(ssl_ctx->mutex); RSA_free(ssl_ctx->rsa_ctx); RNG_terminate(); free(ssl_ctx); @@ -252,24 +253,20 @@ EXP_FUNC void STDCALL ssl_free(SSL *ssl) ssl_ctx = ssl->ssl_ctx; + SSL_CTX_LOCK(ssl_ctx->mutex); + /* adjust the server SSL list */ if (ssl->prev) - { ssl->prev->next = ssl->next; - } else - { - ssl_ctx->sess_head = ssl->next; - } + ssl_ctx->head = ssl->next; if (ssl->next) - { ssl->next->prev = ssl->prev; - } else - { - ssl_ctx->sess_tail = ssl->prev; - } + ssl_ctx->tail = ssl->prev; + + SSL_CTX_UNLOCK(ssl_ctx->mutex); /* may already be free - but be sure */ free(ssl->all_pkts); @@ -278,7 +275,6 @@ EXP_FUNC void STDCALL ssl_free(SSL *ssl) free(ssl->encrypt_ctx); free(ssl->decrypt_ctx); free(ssl->master_secret); - buf_free(&ssl->bm_buf); #ifdef CONFIG_SSL_CERT_VERIFICATION x509_free(ssl->x509_ctx); #endif @@ -315,15 +311,28 @@ EXP_FUNC int STDCALL ssl_read(SSL *ssl, uint8_t **in_data) EXP_FUNC int STDCALL ssl_write(SSL *ssl, const uint8_t *out_data, int out_len) { - int ret = send_packet(ssl, PT_APP_PROTOCOL_DATA, out_data, out_len); + int n = out_len, nw, i, tot = 0; - /* make sure there is no problem with overflow due to padding etc */ - if (ret > out_len) + /* maximum size of a TLS packet is around 16kB, so fragment */ + do { - ret = out_len; - } + nw = n; - return ret; + if (nw > RT_MAX_PLAIN_LENGTH) /* fragment if necessary */ + nw = RT_MAX_PLAIN_LENGTH; + + if ((i = send_packet(ssl, PT_APP_PROTOCOL_DATA, + &out_data[tot], nw)) <= 0) + { + out_len = i; /* an error */ + break; + } + + tot += i; + n -= i; + } while (n > 0); + + return out_len; } /** @@ -411,9 +420,7 @@ int add_cert_auth(SSLCTX *ssl_ctx, const uint8_t *buf, int len) /* recurse? */ if (len > 0) - { ret = add_cert_auth(ssl_ctx, &buf[offset], len); - } error: return ret; @@ -459,17 +466,24 @@ EXP_FUNC const char * STDCALL ssl_get_cert_dn(SSL *ssl, int component) */ EXP_FUNC SSL * STDCALL ssl_find(SSLCTX *ssl_ctx, int client_fd) { - SSL *ssl = ssl_ctx->sess_head; + SSL *ssl; + + SSL_CTX_LOCK(ssl_ctx->mutex); + ssl = ssl_ctx->head; /* search through all the ssl entries */ while (ssl) { if (ssl->client_fd == client_fd) + { + SSL_CTX_UNLOCK(ssl_ctx->mutex); return ssl; + } ssl = ssl->next; } + SSL_CTX_UNLOCK(ssl_ctx->mutex); return NULL; } @@ -526,31 +540,33 @@ SSL *ssl_new(SSLCTX *ssl_ctx, int client_fd) SSL *ssl = (SSL *)calloc(1, sizeof(SSL)); ssl->ssl_ctx = ssl_ctx; ssl->need_bytes = SSL_RECORD_SIZE; /* need a record */ - ssl->bm_buf = buf_new(); ssl->client_fd = client_fd; ssl->flag = SSL_NEED_RECORD; ssl->certs = ssl_ctx->certs; ssl->chain_length = ssl_ctx->chain_length; + ssl->bm_data = ssl->bm_all_data+BM_RECORD_OFFSET; /* space at the start */ #ifdef CONFIG_ENABLE_VERIFICATION ssl->ca_cert_ctx = ssl_ctx->ca_cert_ctx; #endif /* a bit hacky but saves a few bytes of memory */ ssl->flag |= ssl_ctx->options; + SSL_CTX_LOCK(ssl_ctx->mutex); - /* build up a linked list, so we can remove it all later */ - if (ssl_ctx->sess_head == NULL) + if (ssl_ctx->head == NULL) { - ssl_ctx->sess_head = ssl; - ssl_ctx->sess_tail = ssl; + ssl_ctx->head = ssl; + ssl_ctx->tail = ssl; } else { - ssl->prev = ssl_ctx->sess_tail; - ssl_ctx->sess_tail->next = ssl; - ssl_ctx->sess_tail = ssl; + ssl->prev = ssl_ctx->tail; + ssl_ctx->tail->next = ssl; + ssl_ctx->tail = ssl; } + SSL_CTX_UNLOCK(ssl_ctx->mutex); + return ssl; } @@ -905,32 +921,30 @@ static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt) */ static int send_raw_packet(SSL *ssl, uint8_t protocol) { - uint8_t *rec_buf = ssl->bm_buf.pre_data; - int pkt_size = SSL_RECORD_SIZE+ssl->bm_buf.index; + uint8_t *rec_buf = ssl->bm_all_data; + int pkt_size = SSL_RECORD_SIZE+ssl->bm_index; int ret; rec_buf[0] = protocol; rec_buf[1] = 0x03; /* version = 3.1 (TLS) */ rec_buf[2] = 0x01; - rec_buf[3] = ssl->bm_buf.index >> 8; - rec_buf[4] = ssl->bm_buf.index & 0xff; + rec_buf[3] = ssl->bm_index >> 8; + rec_buf[4] = ssl->bm_index & 0xff; - DISPLAY_BYTES(ssl, "sending %d bytes", ssl->bm_buf.pre_data, + DISPLAY_BYTES(ssl, "sending %d bytes", ssl->bm_all_data, pkt_size, pkt_size); - ret = SOCKET_WRITE(ssl->client_fd, ssl->bm_buf.pre_data, pkt_size); + if ((ret = SOCKET_WRITE(ssl->client_fd, + ssl->bm_all_data, pkt_size)) < 0) + ret = SSL_ERROR_CONN_LOST; SET_SSL_FLAG(SSL_NEED_RECORD); /* reset for next time */ - ssl->bm_buf.index = 0; + ssl->bm_index = 0; - if (ret < 0) - { - ret = SSL_ERROR_CONN_LOST; - } - else if (protocol != PT_APP_PROTOCOL_DATA) + if (protocol != PT_APP_PROTOCOL_DATA) { /* always return SSL_OK during handshake */ - return ret = SSL_OK; + ret = SSL_OK; } return ret; @@ -942,18 +956,16 @@ static int send_raw_packet(SSL *ssl, uint8_t protocol) int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length) { int msg_length = length; - ssl->bm_buf.index = msg_length; - buf_grow(&ssl->bm_buf, msg_length+32); + int ret, pad_bytes = 0; + ssl->bm_index = msg_length; /* if our state is bad, don't bother */ if (ssl->hs_status == SSL_ERROR_DEAD) - { return SSL_ERROR_CONN_LOST; - } if (in) /* has the buffer already been initialised? */ { - memcpy(ssl->bm_buf.data, in, length); + memcpy(ssl->bm_data, in, length); } if (IS_SET_SSL_FLAG(SSL_TX_ENCRYPTED)) @@ -966,55 +978,56 @@ int send_packet(SSL *ssl, uint8_t protocol, const uint8_t *in, int length) if (protocol == PT_HANDSHAKE_PROTOCOL) { - DISPLAY_STATE(ssl, 1, ssl->bm_buf.data[0], 0); + DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0); - if (ssl->bm_buf.data[0] != HS_HELLO_REQUEST) + if (ssl->bm_data[0] != HS_HELLO_REQUEST) { - add_packet(ssl, ssl->bm_buf.data, ssl->bm_buf.index); + add_packet(ssl, ssl->bm_data, ssl->bm_index); } } /* add the packet digest */ msg_length += ssl->cipher_info->digest_size; - ssl->bm_buf.index = msg_length; - add_hmac_digest(ssl, mode, ssl->bm_buf.data, length, - &ssl->bm_buf.data[length]); + ssl->bm_index = msg_length; + add_hmac_digest(ssl, mode, ssl->bm_data, length, + &ssl->bm_data[length]); /* add padding? */ if (ssl->cipher_info->padding_size) { int last_blk_size = msg_length%ssl->cipher_info->padding_size; - int pad_bytes = ssl->cipher_info->padding_size - last_blk_size; + pad_bytes = ssl->cipher_info->padding_size - last_blk_size; /* ensure we always have at least 1 padding byte */ if (pad_bytes == 0) - { pad_bytes += ssl->cipher_info->padding_size; - } - memset(&ssl->bm_buf.data[msg_length], pad_bytes-1, pad_bytes); + memset(&ssl->bm_data[msg_length], pad_bytes-1, pad_bytes); msg_length += pad_bytes; - ssl->bm_buf.index = msg_length; + ssl->bm_index = msg_length; } - DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_buf.data, msg_length); + DISPLAY_BYTES(ssl, "unencrypted write", ssl->bm_data, msg_length); increment_write_sequence(ssl); /* now encrypt the packet */ - ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_buf.data, - ssl->bm_buf.data, msg_length); + ssl->cipher_info->encrypt(ssl->encrypt_ctx, ssl->bm_data, + ssl->bm_data, msg_length); } else if (protocol == PT_HANDSHAKE_PROTOCOL) { - DISPLAY_STATE(ssl, 1, ssl->bm_buf.data[0], 0); + DISPLAY_STATE(ssl, 1, ssl->bm_data[0], 0); - if (ssl->bm_buf.data[0] != HS_HELLO_REQUEST) + if (ssl->bm_data[0] != HS_HELLO_REQUEST) { - add_packet(ssl, ssl->bm_buf.data, ssl->bm_buf.index); + add_packet(ssl, ssl->bm_data, ssl->bm_index); } } - return send_raw_packet(ssl, protocol); + if ((ret = send_raw_packet(ssl, protocol)) <= 0) + return ret; + + return length; /* just return what we wanted to send */ } /** @@ -1125,9 +1138,8 @@ int basic_read(SSL *ssl, uint8_t **in_data) int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); uint8_t *buf; - buf_grow(&ssl->bm_buf, ssl->need_bytes); - buf = ssl->bm_buf.data; - read_len = SOCKET_READ(ssl->client_fd, &buf[ssl->bm_buf.index], + buf = ssl->bm_data; + read_len = SOCKET_READ(ssl->client_fd, &buf[ssl->bm_index], ssl->need_bytes-ssl->got_bytes); /* connection has gone, so die */ @@ -1139,17 +1151,16 @@ int basic_read(SSL *ssl, uint8_t **in_data) } DISPLAY_BYTES(ssl, "received %d bytes", - &ssl->bm_buf.data[ssl->bm_buf.index], read_len, read_len); + &ssl->bm_data[ssl->bm_index], read_len, read_len); ssl->got_bytes += read_len; - ssl->bm_buf.index += read_len; + ssl->bm_index += read_len; /* haven't quite got what we want, so try again later */ if (ssl->got_bytes < ssl->need_bytes) - { return SSL_OK; - } + read_len = ssl->got_bytes; ssl->got_bytes = 0; if (IS_SET_SSL_FLAG(SSL_NEED_RECORD)) @@ -1162,14 +1173,21 @@ int basic_read(SSL *ssl, uint8_t **in_data) add_packet(ssl, &buf[2], 3); ret = process_sslv23_client_hello(ssl); #else - printf("Error: no SSLv23 handshaking allowed\n"); - TTY_FLUSH(); + printf("Error: no SSLv23 handshaking allowed\n"); TTY_FLUSH(); ret = SSL_ERROR_NOT_SUPPORTED; #endif goto error; /* not an error - just get out of here */ } ssl->need_bytes = (buf[3] << 8) + buf[4]; + + /* do we violate the spec with the message size? */ + if (ssl->need_bytes > RT_MAX_PLAIN_LENGTH+RT_EXTRA-BM_RECORD_OFFSET) + { + ret = SSL_ERROR_INVALID_PROT_MSG; + goto error; + } + CLR_SSL_FLAG(SSL_NEED_RECORD); memcpy(ssl->record_buf, buf, 3); /* store for hmac */ is_record = 1; @@ -1182,9 +1200,7 @@ int basic_read(SSL *ssl, uint8_t **in_data) } if (is_record) - { ssl->record_type = buf[0]; - } else if (IS_SET_SSL_FLAG(SSL_RX_ENCRYPTED)) { ssl->cipher_info->decrypt(ssl->decrypt_ctx, buf, buf, read_len); @@ -1224,8 +1240,8 @@ int basic_read(SSL *ssl, uint8_t **in_data) break; case PT_APP_PROTOCOL_DATA: - *in_data = ssl->bm_buf.data; /* point to the work buffer */ - (*in_data)[read_len] = 0; /* null terminate just in case */ + *in_data = ssl->bm_data; /* point to the work buffer */ + (*in_data)[read_len] = 0; /* null terminate just in case */ ret = read_len; break; @@ -1242,12 +1258,10 @@ int basic_read(SSL *ssl, uint8_t **in_data) } error: - ssl->bm_buf.index = 0; /* reset to go again */ + ssl->bm_index = 0; /* reset to go again */ if (ret < SSL_OK && in_data) /* if all wrong, then clear this buffer ptr */ - { *in_data = NULL; - } return ret; } @@ -1277,13 +1291,11 @@ static int do_handshake(SSL *ssl, uint8_t *buf, int read_len) } hs_len += SSL_HS_HDR_SIZE; /* adjust for when adding packets */ - ssl->bm_buf.index = hs_len; /* store the size and check later */ + ssl->bm_index = hs_len; /* store the size and check later */ DISPLAY_STATE(ssl, 0, handshake_type, 0); if (handshake_type != HS_CERT_VERIFY && handshake_type != HS_HELLO_REQUEST) - { add_packet(ssl, buf, hs_len); - } #if defined(CONFIG_SSL_ENABLE_CLIENT) ret = is_client ? @@ -1295,9 +1307,7 @@ static int do_handshake(SSL *ssl, uint8_t *buf, int read_len) /* just use recursion to get the rest */ if (hs_len < read_len && ret == SSL_OK) - { ret = do_handshake(ssl, &buf[hs_len], read_len-hs_len); - } error: return ret; @@ -1322,7 +1332,7 @@ int send_change_cipher_spec(SSL *ssl) */ int send_finished(SSL *ssl) { - uint8_t *buf = ssl->bm_buf.data; + uint8_t *buf = ssl->bm_data; buf[0] = HS_FINISHED; buf[1] = 0; @@ -1365,9 +1375,7 @@ int send_alert(SSL *ssl, int error_code) #ifdef CONFIG_SSL_FULL_MODE if (IS_SET_SSL_FLAG(SSL_DISPLAY_STATES)) - { ssl_display_error(error_code); - } #endif switch (error_code) @@ -1424,25 +1432,21 @@ int send_alert(SSL *ssl, int error_code) */ int process_finished(SSL *ssl, int hs_len) { - uint8_t *buf = ssl->bm_buf.data; + uint8_t *buf = ssl->bm_data; int ret = SSL_OK; int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); int resume = IS_SET_SSL_FLAG(SSL_SESSION_RESUME); - PARANOIA_CHECK(ssl->bm_buf.index, SSL_FINISHED_HASH_SIZE+4); + PARANOIA_CHECK(ssl->bm_index, SSL_FINISHED_HASH_SIZE+4); /* check that we all work before we continue */ if (memcmp(ssl->final_finish_mac, &buf[4], SSL_FINISHED_HASH_SIZE)) - { return SSL_ERROR_FINISHED_INVALID; - } if ((!is_client && !resume) || (is_client && resume)) { if ((ret = send_change_cipher_spec(ssl)) == SSL_OK) - { ret = send_finished(ssl); - } } /* Don't need this stuff anymore */ @@ -1470,7 +1474,7 @@ error: int send_certificate(SSL *ssl) { int i = 0; - uint8_t *buf = ssl->bm_buf.data; + uint8_t *buf = ssl->bm_data; int offset = 7; int chain_length; @@ -1485,7 +1489,6 @@ int send_certificate(SSL *ssl) buf[offset++] = 0; buf[offset++] = cert->size >> 8; /* cert 1 length */ buf[offset++] = cert->size & 0xff; - buf_grow(&ssl->bm_buf, offset + cert->size); memcpy(&buf[offset], cert->buf, cert->size); offset += cert->size; i++; @@ -1497,7 +1500,7 @@ int send_certificate(SSL *ssl) chain_length += 3; buf[2] = chain_length >> 8; /* handshake length */ buf[3] = chain_length & 0xff; - ssl->bm_buf.index = offset; + ssl->bm_index = offset; return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); } @@ -1516,10 +1519,9 @@ SSL_SESS *ssl_session_update(int max_sessions, /* no sessions? Then bail */ if (max_sessions == 0) - { return NULL; - } + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); if (session_id) { for (i = 0; i < max_sessions; i++) @@ -1543,6 +1545,7 @@ SSL_SESS *ssl_session_update(int max_sessions, memcpy(ssl->master_secret, ssl_sessions[i]->master_secret, SSL_SECRET_SIZE); SET_SSL_FLAG(SSL_SESSION_RESUME); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); return ssl_sessions[i]; /* a session was found */ } } @@ -1558,6 +1561,7 @@ SSL_SESS *ssl_session_update(int max_sessions, ssl_sessions[i] = (SSL_SESS *)calloc(1, sizeof(SSL_SESS)); ssl_sessions[i]->conn_time = tm; ssl->session_index = i; + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); return ssl_sessions[i]; /* return the session object */ } else if (ssl_sessions[i]->conn_time <= oldest_sess_time) @@ -1573,6 +1577,7 @@ SSL_SESS *ssl_session_update(int max_sessions, oldest_sess->conn_time = tm; memset(oldest_sess->session_id, 0, sizeof(SSL_SESSION_ID_SIZE)); memset(oldest_sess->master_secret, 0, sizeof(SSL_SECRET_SIZE)); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); return oldest_sess; } @@ -1593,11 +1598,15 @@ static void session_free(SSL_SESS *ssl_sessions[], int sess_index) */ void kill_ssl_session(SSL_SESS **ssl_sessions, SSL *ssl) { + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); + if (ssl->ssl_ctx->num_sessions) { session_free(ssl_sessions, ssl->session_index); ssl->session = NULL; } + + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); } #endif /* CONFIG_SSL_SKELETON_MODE */ @@ -1684,10 +1693,10 @@ EXP_FUNC int STDCALL ssl_verify_cert(SSL *ssl) int process_certificate(SSL *ssl, X509_CTX **x509_ctx) { int ret = SSL_OK; - int pkt_size = ssl->bm_buf.index; + int pkt_size = ssl->bm_index; int cert_size, offset = 5; - int total_cert_size = (ssl->bm_buf.data[offset]<<8) + - ssl->bm_buf.data[offset+1]; + int total_cert_size = (ssl->bm_data[offset]<<8) + + ssl->bm_data[offset+1]; int is_client = IS_SET_SSL_FLAG(SSL_IS_CLIENT); X509_CTX **chain = x509_ctx; offset += 2; @@ -1697,10 +1706,10 @@ int process_certificate(SSL *ssl, X509_CTX **x509_ctx) while (offset < total_cert_size) { offset++; /* skip empty char */ - cert_size = (ssl->bm_buf.data[offset]<<8) + ssl->bm_buf.data[offset+1]; + cert_size = (ssl->bm_data[offset]<<8) + ssl->bm_data[offset+1]; offset += 2; - if (x509_new(&ssl->bm_buf.data[offset], NULL, chain)) + if (x509_new(&ssl->bm_data[offset], NULL, chain)) { ret = SSL_ERROR_BAD_CERTIFICATE; goto error; @@ -1983,6 +1992,15 @@ void DISPLAY_ALERT(SSL *ssl, int alert) #endif /* CONFIG_SSL_FULL_MODE */ +/** + * Return the version of this library. + */ +EXP_FUNC const char * STDCALL ssl_version() +{ + static const char * axtls_version = AXTLS_VERSION " " __DATE__; + return axtls_version; +} + /** * Enable the various language bindings to work regardless of the * configuration - they just return an error statement and a bad return code. diff --git a/ssl/tls1.h b/ssl/tls1.h index fc343e512..f21d9a6cd 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -28,6 +28,31 @@ extern "C" { #endif +#include "version.h" + +/* Mutexing definitions */ +#if defined(CONFIG_SSLCTX_MUTEXING) +#if defined(WIN32) +#define SSL_CTX_MUTEX_TYPE HANDLE +#define SSL_CTX_MUTEX_INIT(A) A=CreateMutex(0, FALSE, 0) +#define SSL_CTX_MUTEX_DESTROY(A) CloseHandle(A) +#define SSL_CTX_LOCK(A) WaitForSingleObject(A, INFINITE) +#define SSL_CTX_UNLOCK(A) ReleaseMutex(A) +#else +#include +#define SSL_CTX_MUTEX_TYPE pthread_mutex_t +#define SSL_CTX_MUTEX_INIT(A) pthread_mutex_init(&A, NULL) +#define SSL_CTX_MUTEX_DESTROY(A) pthread_mutex_destroy(&A) +#define SSL_CTX_LOCK(A) pthread_mutex_lock(&A) +#define SSL_CTX_UNLOCK(A) pthread_mutex_unlock(&A) +#endif +#else /* no mutexing */ +#define SSL_CTX_MUTEX_INIT(A) +#define SSL_CTX_MUTEX_DESTROY(A) +#define SSL_CTX_LOCK(A) +#define SSL_CTX_UNLOCK(A) +#endif + #define SSL_RANDOM_SIZE 32 #define SSL_SECRET_SIZE 48 #define SSL_FINISHED_HASH_SIZE 12 @@ -52,6 +77,9 @@ extern "C" { #define IS_SET_SSL_FLAG(A) (ssl->flag & A) #define MAX_KEY_BYTE_SIZE 512 /* for a 4096 bit key */ +#define RT_MAX_PLAIN_LENGTH 16384 +#define RT_EXTRA 1024 +#define BM_RECORD_OFFSET 5 #ifdef CONFIG_SSL_SKELETON_MODE #define NUM_PROTOCOLS 1 @@ -138,11 +166,13 @@ struct _SSL uint8_t *key_block; void *encrypt_ctx; void *decrypt_ctx; - BUF_MEM bm_buf; + uint8_t bm_all_data[RT_MAX_PLAIN_LENGTH+RT_EXTRA]; + uint8_t *bm_data; + int bm_index; struct _SSL *next; /* doubly linked list */ struct _SSL *prev; SSL_CERT *certs; - struct _SSLCTX *ssl_ctx; /* back reference to a clnt/svr ctx */ + struct _SSLCTX *ssl_ctx; /* back reference to a clnt/svr ctx */ #ifndef CONFIG_SSL_SKELETON_MODE uint16_t session_index; SSL_SESS *session; @@ -172,13 +202,16 @@ struct _SSLCTX #ifdef CONFIG_SSL_CERT_VERIFICATION CA_CERT_CTX *ca_cert_ctx; #endif - SSL *sess_head; - SSL *sess_tail; + SSL *head; + SSL *tail; SSL_CERT certs[CONFIG_SSL_MAX_CERTS]; #ifndef CONFIG_SSL_SKELETON_MODE uint16_t num_sessions; SSL_SESS **ssl_sessions; #endif +#ifdef CONFIG_SSLCTX_MUTEXING + SSL_CTX_MUTEX_TYPE mutex; +#endif }; typedef struct _SSLCTX SSLCTX; diff --git a/ssl/tls1_clnt.c b/ssl/tls1_clnt.c index b9642b34e..7dc9c4d43 100644 --- a/ssl/tls1_clnt.c +++ b/ssl/tls1_clnt.c @@ -117,7 +117,7 @@ int do_client_connect(SSL *ssl) int ret = SSL_OK; send_client_hello(ssl); /* send the client hello */ - ssl->bm_buf.index = 0; + ssl->bm_index = 0; ssl->next_state = HS_SERVER_HELLO; ssl->hs_status = SSL_NOT_OK; /* not connected */ @@ -151,7 +151,7 @@ int do_client_connect(SSL *ssl) */ static int send_client_hello(SSL *ssl) { - uint8_t *buf = ssl->bm_buf.data; + uint8_t *buf = ssl->bm_data; time_t tm = time(NULL); uint8_t *tm_ptr = &buf[6]; /* time will go here */ int i, offset; @@ -186,19 +186,19 @@ static int send_client_hello(SSL *ssl) buf[offset++] = 0; } - buf[offset++] = 0; /* number of ciphers */ - buf[offset++] = NUM_PROTOCOLS*2; /* number of ciphers */ + buf[offset++] = 0; /* number of ciphers */ + buf[offset++] = NUM_PROTOCOLS*2;/* number of ciphers */ /* put all our supported protocols in our request */ for (i = 0; i < NUM_PROTOCOLS; i++) { - buf[offset++] = 0; /* cipher we are using */ + buf[offset++] = 0; /* cipher we are using */ buf[offset++] = ssl_prot_prefs[i]; } - buf[offset++] = 1; /* no compression */ + buf[offset++] = 1; /* no compression */ buf[offset++] = 0; - buf[3] = offset - 4; /* handshake size */ + buf[3] = offset - 4; /* handshake size */ return send_packet(ssl, PT_HANDSHAKE_PROTOCOL, NULL, offset); } @@ -208,8 +208,8 @@ static int send_client_hello(SSL *ssl) */ static int process_server_hello(SSL *ssl) { - uint8_t *buf = ssl->bm_buf.data; - int pkt_size = ssl->bm_buf.index; + uint8_t *buf = ssl->bm_data; + int pkt_size = ssl->bm_index; int offset; int version = (buf[4] << 4) + buf[5]; int num_sessions = ssl->ssl_ctx->num_sessions; @@ -217,9 +217,7 @@ static int process_server_hello(SSL *ssl) /* check that we are talking to a TLSv1 server */ if (version != 0x31) - { return SSL_ERROR_INVALID_VERSION; - } /* get the server random value */ memcpy(ssl->server_random, &buf[6], SSL_RANDOM_SIZE); @@ -260,7 +258,7 @@ static int process_server_hello_done(SSL *ssl) */ static int send_client_key_xchg(SSL *ssl) { - uint8_t *buf = ssl->bm_buf.data; + uint8_t *buf = ssl->bm_data; uint8_t premaster_secret[SSL_SECRET_SIZE]; int enc_secret_size = -1; @@ -271,8 +269,13 @@ static int send_client_key_xchg(SSL *ssl) premaster_secret[1] = 0x01; get_random(SSL_SECRET_SIZE-2, &premaster_secret[2]); DISPLAY_RSA(ssl, "send_client_key_xchg", ssl->x509_ctx->rsa_ctx); + + /* rsa_ctx->bi_ctx is not thread-safe */ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); enc_secret_size = RSA_encrypt(ssl->x509_ctx->rsa_ctx, premaster_secret, SSL_SECRET_SIZE, &buf[6], 0); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); + buf[2] = (enc_secret_size + 2) >> 8; buf[3] = (enc_secret_size + 2) & 0xff; buf[4] = enc_secret_size >> 8; @@ -298,7 +301,7 @@ static int process_cert_req(SSL *ssl) */ static int send_cert_verify(SSL *ssl) { - uint8_t *buf = ssl->bm_buf.data; + uint8_t *buf = ssl->bm_data; uint8_t dgst[MD5_SIZE+SHA1_SIZE]; RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; int n, ret; @@ -309,7 +312,11 @@ static int send_cert_verify(SSL *ssl) buf[1] = 0; finished_digest(ssl, NULL, dgst); /* calculate the digest */ + + /* rsa_ctx->bi_ctx is not thread-safe */ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); n = RSA_encrypt(rsa_ctx, dgst, sizeof(dgst), &buf[6], 1); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); if (n == 0) { diff --git a/ssl/tls1_svr.c b/ssl/tls1_svr.c index ad463def3..9ad3a98d8 100644 --- a/ssl/tls1_svr.c +++ b/ssl/tls1_svr.c @@ -45,10 +45,7 @@ EXP_FUNC SSL * STDCALL ssl_server_new(SSLCTX *ssl_ctx, int client_fd) #ifdef CONFIG_SSL_FULL_MODE if (ssl_ctx->chain_length == 0) - { - printf("Warning - no server certificate defined\n"); - TTY_FLUSH(); - } + printf("Warning - no server certificate defined\n"); TTY_FLUSH(); #endif return ssl; @@ -67,9 +64,7 @@ int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) { case HS_CLIENT_HELLO: if ((ret = process_client_hello(ssl)) == SSL_OK) - { ret = send_server_hello_sequence(ssl); - } break; #ifdef CONFIG_SSL_CERT_VERIFICATION @@ -107,9 +102,9 @@ int do_svr_handshake(SSL *ssl, int handshake_type, uint8_t *buf, int hs_len) */ static int process_client_hello(SSL *ssl) { - uint8_t *buf = ssl->bm_buf.data; + uint8_t *buf = ssl->bm_data; uint8_t *record_buf = ssl->record_buf; - int pkt_size = ssl->bm_buf.index; + int pkt_size = ssl->bm_index; int i, j, cs_len, id_len, offset = 6 + SSL_RANDOM_SIZE; int version = (record_buf[1] << 4) + record_buf[2]; int ret = SSL_OK; @@ -169,7 +164,7 @@ error: */ int process_sslv23_client_hello(SSL *ssl) { - uint8_t *buf = ssl->bm_buf.data; + uint8_t *buf = ssl->bm_data; int bytes_needed = ((buf[0] & 0x7f) << 8) + buf[1]; int version = (buf[3] << 4) + buf[4]; int ret = SSL_OK; @@ -291,7 +286,7 @@ static int send_server_hello_sequence(SSL *ssl) */ static int send_server_hello(SSL *ssl) { - uint8_t *buf = ssl->bm_buf.data; + uint8_t *buf = ssl->bm_data; int offset = 0; buf[0] = HS_SERVER_HELLO; @@ -358,8 +353,8 @@ static int send_server_hello_done(SSL *ssl) */ static int process_client_key_xchg(SSL *ssl) { - uint8_t *buf = ssl->bm_buf.data; - int pkt_size = ssl->bm_buf.index; + uint8_t *buf = ssl->bm_data; + int pkt_size = ssl->bm_index; int premaster_size, secret_length = (buf[2] << 8) + buf[3]; uint8_t premaster_secret[MAX_KEY_BYTE_SIZE]; RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx; @@ -370,12 +365,14 @@ static int process_client_key_xchg(SSL *ssl) /* is there an extra size field? */ if ((secret_length - 2) == rsa_ctx->num_octets) - { offset += 2; - } PARANOIA_CHECK(pkt_size, rsa_ctx->num_octets+offset); + + /* rsa_ctx->bi_ctx is not thread-safe */ + SSL_CTX_LOCK(ssl->ssl_ctx->mutex); premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret, 1); + SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex); if (premaster_size != SSL_SECRET_SIZE || premaster_secret[0] != 0x03 || /* check version is 3.1 (TLS) */ @@ -420,8 +417,8 @@ static int send_certificate_request(SSL *ssl) */ static int process_cert_verify(SSL *ssl) { - uint8_t *buf = ssl->bm_buf.data; - int pkt_size = ssl->bm_buf.index; + uint8_t *buf = ssl->bm_data; + int pkt_size = ssl->bm_index; uint8_t dgst_buf[MAX_KEY_BYTE_SIZE]; uint8_t dgst[MD5_SIZE+SHA1_SIZE]; X509_CTX *x509_ctx = ssl->x509_ctx;