diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 000000000..974d6357e --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,12 @@ +Changes since 1.0.0 + +* AES should now work on 16bit processors (there was an alignment problem) +* Various freed objects are cleared before freeing. +* Header files now installed in /usr/local/include/axTLS +* -DCYGWIN replaced with -DCONFIG_PLATFORM_CYGWIN (and the same for solaris) + +axhttpd Changes +* Header file issue fixed (in mime_types.c) +* chroot() now used for better security +* Authentication implemented +* diff --git a/Makefile b/Makefile index 33c1debe4..549fb8a88 100644 --- a/Makefile +++ b/Makefile @@ -74,10 +74,20 @@ win32_demo: install: $(PREFIX) all cp --no-dereference $(STAGE)/libax* $(PREFIX)/lib chmod 755 $(PREFIX)/lib/libax* - -install -m 755 $(STAGE)/ax* $(PREFIX)/bin > /dev/null 2>&1 + -install -m 755 $(STAGE)/ax* $(PREFIX)/bin ifdef CONFIG_PERL_BINDINGS - -install -m 755 $(STAGE)/axtlsp.pm `perl -e 'use Config; print $$Config{installarchlib};'` > /dev/null 2>&1 + -install -m 755 $(STAGE)/axtlsp.pm `perl -e 'use Config; print $$Config{installarchlib};'` endif + @mkdir -p -m 755 $(PREFIX)/include/axTLS + -install -m 644 ssl/bigint.h $(PREFIX)/include/axTLS + -install -m 644 ssl/bigint_impl.h $(PREFIX)/include/axTLS + -install -m 644 ssl/crypto.h $(PREFIX)/include/axTLS + -install -m 644 ssl/os_port.h $(PREFIX)/include/axTLS + -install -m 644 ssl/bigint.h $(PREFIX)/include/axTLS + -install -m 644 ssl/ssl.h $(PREFIX)/include/axTLS + -install -m 644 ssl/tls1.h $(PREFIX)/include/axTLS + -install -m 644 ssl/version.h $(PREFIX)/include/axTLS + -install -m 644 config/config.h $(PREFIX)/include/axTLS installclean: -@rm $(PREFIX)/lib/libax* > /dev/null 2>&1 diff --git a/config/makefile.conf b/config/makefile.conf index 41e66702f..58f66f60d 100644 --- a/config/makefile.conf +++ b/config/makefile.conf @@ -79,7 +79,7 @@ LD=$(CC) # Solaris ifdef CONFIG_PLATFORM_SOLARIS -CFLAGS += -DSOLARIS +CFLAGS += -DCONFIG_PLATFORM_SOLARIS LDFLAGS += -lsocket -lnsl -lc LDSHARED = -G # Linux/Cygwin @@ -89,7 +89,7 @@ LDSHARED = -shared ifndef CONFIG_PLATFORM_CYGWIN CFLAGS += -fPIC else -CFLAGS += -DCYGWIN +CFLAGS += -DCONFIG_PLATFORM_CYGWIN endif endif diff --git a/httpd/Config.in b/httpd/Config.in index 8d1000e02..531f9c882 100644 --- a/httpd/Config.in +++ b/httpd/Config.in @@ -13,6 +13,14 @@ config CONFIG_HTTP_STATIC_BUILD Select y if you want axhttp to be a static build (i.e. don't use the axtls shared library or dll). +config CONFIG_HTTP_PORT + int "HTTP port" + default 80 + help + The port number of the normal HTTP server. + + You must be a root user in order to use the default port. + config CONFIG_HTTP_HTTPS_PORT int "HTTPS port" default 443 @@ -39,14 +47,6 @@ config CONFIG_HTTP_WEBROOT The location of the web root in relation to axhttpd. This is the directory where index.html lives. -config CONFIG_HTTP_PORT - int "HTTP port" - default 80 - help - The port number of the normal HTTP server. - - You must be a root user in order to use the default port. - config CONFIG_HTTP_TIMEOUT int "Timeout" default 5 @@ -79,6 +79,12 @@ config CONFIG_HTTP_PERM_CHECK Enable permissions checking on the directories before reading the files in them. +config CONFIG_HTTP_HAS_AUTHORIZATION + bool "Enable authorization" + default n + help + Pages/directories can have passwords associated with them. + config CONFIG_HTTP_HAS_IPV6 bool "Enable IPv6" default n diff --git a/httpd/Makefile b/httpd/Makefile index 442dca403..71ea462a6 100644 --- a/httpd/Makefile +++ b/httpd/Makefile @@ -54,7 +54,7 @@ else web_server : $(TARGET) OBJ= \ - main.o \ + axhttpd.o \ proc.o \ mime_types.o diff --git a/httpd/axhttp.h b/httpd/axhttp.h index dde47e60d..cce1567b1 100644 --- a/httpd/axhttp.h +++ b/httpd/axhttp.h @@ -77,6 +77,9 @@ struct connstruct uint8_t is_ssl; uint8_t close_when_done; uint8_t modified_since; +#if defined(CONFIG_HTTP_HAS_AUTHORIZATION) + char authorization[MAXREQUESTLENGTH]; +#endif }; struct serverstruct @@ -103,9 +106,6 @@ extern struct connstruct *freeconns; extern struct cgiextstruct *cgiexts; #endif -// Conf global prototypes -extern char *webroot; - // conn.c prototypes void removeconnection(struct connstruct *cn); diff --git a/httpd/main.c b/httpd/axhttpd.c similarity index 97% rename from httpd/main.c rename to httpd/axhttpd.c index dd0e09fdf..cd899f9cf 100644 --- a/httpd/main.c +++ b/httpd/axhttpd.c @@ -27,7 +27,6 @@ struct serverstruct *servers; struct connstruct *usedconns; struct connstruct *freeconns; -char *webroot = CONFIG_HTTP_WEBROOT; static void addtoservers(int sd); static int openlistener(int port); @@ -86,11 +85,12 @@ static void die(int sigtype) int main(int argc, char *argv[]) { + static char *webroot = CONFIG_HTTP_WEBROOT; fd_set rfds, wfds; struct connstruct *tp, *to; struct serverstruct *sp; int rnum, wnum, active; - int webrootlen, i; + int i; time_t currtime; #ifdef WIN32 @@ -98,12 +98,6 @@ int main(int argc, char *argv[]) WSADATA wsaData; WSAStartup(wVersionRequested,&wsaData); #else - if (getuid() == 0) /* change our uid if we are root */ - { - setgid(32767); - setuid(32767); - } - signal(SIGQUIT, die); signal(SIGPIPE, SIG_IGN); #if defined(CONFIG_HTTP_HAS_CGI) @@ -122,12 +116,8 @@ int main(int argc, char *argv[]) freeconns->next = tp; } - webrootlen = strlen(webroot); - - if (webroot[webrootlen-1] == '/') - webroot[webrootlen-1] = '\0'; - - if (isdir(webroot) == 0) + /* change to webroot for better security */ + if (chroot(webroot)) { #ifdef CONFIG_HTTP_VERBOSE fprintf(stderr, "'%s' is not a directory\n", webroot); @@ -135,6 +125,11 @@ int main(int argc, char *argv[]) exit(1); } +#ifndef WIN32 + setgid(32767); + setuid(32767); +#endif + if ((active = openlistener(CONFIG_HTTP_PORT)) == -1) { #ifdef CONFIG_HTTP_VERBOSE diff --git a/httpd/mime_types.c b/httpd/mime_types.c index 1335e7d0d..46e3c3e5e 100644 --- a/httpd/mime_types.c +++ b/httpd/mime_types.c @@ -20,7 +20,7 @@ #include #include #include -#include "os_port.h" +#include "axhttp.h" static const char mime_default[] = "text/plain"; diff --git a/httpd/proc.c b/httpd/proc.c index 9a59908d3..1c746cf2d 100644 --- a/httpd/proc.c +++ b/httpd/proc.c @@ -29,8 +29,7 @@ static int special_read(struct connstruct *cn, void *buf, size_t count); static int special_write(struct connstruct *cn, const uint8_t *buf, size_t count); -static void send404(struct connstruct *cn); -static int procindex(struct connstruct *cn, struct stat *stp); +static void send_error(struct connstruct *cn, int err); static int hexit(char c); static void urldecode(char *buf); static void buildactualfile(struct connstruct *cn); @@ -47,6 +46,9 @@ static int trycgi_withpathinfo(struct connstruct *cn); static void split(char *tp, char *sp[], int maxwords, char sc); static int iscgi(const char *fn); #endif +#ifdef CONFIG_HTTP_HAS_AUTHORIZATION +static int auth_check(struct connstruct *cn); +#endif /* Returns 1 if elems should continue being read, 0 otherwise */ static int procheadelem(struct connstruct *cn, char *buf) @@ -61,10 +63,11 @@ static int procheadelem(struct connstruct *cn, char *buf) *delim = 0; value = delim+1; + printf("BUF %s - value %s\n", buf, value); - if (strcmp(buf, "GET")==0 || - strcmp(buf, "HEAD")==0 || - strcmp(buf, "POST")==0) + if (strcmp(buf, "GET") == 0 || + strcmp(buf, "HEAD") == 0 || + strcmp(buf, "POST") == 0) { if (buf[0] == 'H') cn->reqtype = TYPE_HEAD; @@ -79,8 +82,7 @@ static int procheadelem(struct connstruct *cn, char *buf) if (sanitizefile(value) == 0) { - send404(cn); - removeconnection(cn); + send_error(cn, 404); return 0; } @@ -98,7 +100,6 @@ static int procheadelem(struct connstruct *cn, char *buf) { if (sanitizehost(value) == 0) { - send404(cn); removeconnection(cn); return 0; } @@ -114,6 +115,15 @@ static int procheadelem(struct connstruct *cn, char *buf) /* TODO: parse this date properly with getdate() or similar */ cn->modified_since = 1; } +#ifdef CONFIG_HTTP_HAS_AUTHORIZATION + else if (strcmp(buf, "Authorization:") == 0 && + strncmp(value, "Basic ", 6) == 0) + { + if (base64_decode(&value[6], strlen(&value[6]), + cn->authorization, NULL)) + cn->authorization[0] = 0; /* error */ + } +#endif return 1; } @@ -141,15 +151,13 @@ static void procdirlisting(struct connstruct *cn) if (cn->dirp == INVALID_HANDLE_VALUE) { - send404(cn); - removeconnection(cn); + send_error(cn, 404); return; } #else if ((cn->dirp = opendir(actualfile)) == NULL) { - send404(cn); - removeconnection(cn); + send_error(cn, 404); return; } @@ -205,11 +213,16 @@ void procdodir(struct connstruct *cn) if (file[0] == '.' && file[1] != '.') continue; + /* make sure a '/' is at the end of a directory */ + if (cn->filereq[strlen(cn->filereq)-1] != '/') + strcat(cn->filereq, "/"); + + /* see if the dir + file is another directory */ snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, file); if (isdir(buf)) strcat(file, "/"); - urlencode(file, encbuf); + urlencode(file, encbuf); snprintf(buf, sizeof(buf), "%s
\n", cn->filereq, encbuf, file); } while (special_write(cn, buf, strlen(buf))); @@ -263,6 +276,10 @@ void procreadhead(struct connstruct *cn) buf[rv] = '\0'; next = tp = buf; +#ifdef CONFIG_HTTP_HAS_AUTHORIZATION + cn->authorization[0] = 0; +#endif + /* Split up lines and send to procheadelem() */ while (*next != '\0') { @@ -297,22 +314,22 @@ void procreadhead(struct connstruct *cn) */ void procsendhead(struct connstruct *cn) { - char buf[1024]; - char actualfile[1024]; + char buf[MAXREQUESTLENGTH]; struct stat stbuf; time_t now = cn->timeout - CONFIG_HTTP_TIMEOUT; char date[32]; - strcpy(date, ctime(&now)); - strcpy(actualfile, cn->actualfile); - -#ifdef WIN32 - /* stat() under win32 can't deal with trail slash */ - if (actualfile[strlen(actualfile)-1] == '\\') - actualfile[strlen(actualfile)-1] = 0; +#ifdef CONFIG_HTTP_HAS_AUTHORIZATION + if (auth_check(cn)) + { + removeconnection(cn); + return; + } #endif - if (stat(actualfile, &stbuf) == -1) + strcpy(date, ctime(&now)); + + if (stat(cn->actualfile, &stbuf) == -1) { #if defined(CONFIG_HTTP_HAS_CGI) if (trycgi_withpathinfo(cn) == 0) @@ -323,8 +340,7 @@ void procsendhead(struct connstruct *cn) } #endif - send404(cn); - removeconnection(cn); + send_error(cn, 404); return; } @@ -335,8 +351,7 @@ void procsendhead(struct connstruct *cn) /* Set up CGI script */ if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) { - send404(cn); - removeconnection(cn); + send_error(cn, 404); return; } #endif @@ -346,17 +361,20 @@ void procsendhead(struct connstruct *cn) } #endif + /* look for "index.html"? */ if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { - /* Check to see if this dir has an index file */ - if (procindex(cn, &stbuf) == 0) + char tbuf[MAXREQUESTLENGTH]; + sprintf(tbuf, "%s%s", cn->actualfile, "index.html"); + if (stat(tbuf, &stbuf) != -1) + strcat(cn->actualfile, "index.html"); + else { #if defined(CONFIG_HTTP_DIRECTORIES) /* If not, we do a directory listing of it */ procdirlisting(cn); #else - send404(cn); - removeconnection(cn); + send_error(cn, 404); #endif return; } @@ -368,8 +386,7 @@ void procsendhead(struct connstruct *cn) /* Set up CGI script */ if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) { - send404(cn); - removeconnection(cn); + send_error(cn, 404); return; } @@ -412,14 +429,14 @@ void procsendhead(struct connstruct *cn) else { int flags = O_RDONLY; -#if defined(WIN32) || defined(CYGWIN) +#if defined(WIN32) || defined(CONFIG_PLATFORM_CYGWIN) flags |= O_BINARY; #endif cn->filedesc = open(cn->actualfile, flags); if (cn->filedesc == -1) { - send404(cn); + send_error(cn, 404); removeconnection(cn); return; } @@ -515,23 +532,6 @@ 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 */ -static int procindex(struct connstruct *cn, struct stat *stp) -{ - char tbuf[MAXREQUESTLENGTH]; - - sprintf(tbuf, "%s%s", cn->actualfile, "index.html"); - if (stat(tbuf, stp) != -1) - { - my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH); - return 1; - } - - return 0; -} - #if defined(CONFIG_HTTP_HAS_CGI) static void proccgi(struct connstruct *cn, int has_pathinfo) { @@ -651,8 +651,8 @@ static int trycgi_withpathinfo(struct connstruct *cn) while (fr_rs[i] != NULL) { - snprintf(tpfile, sizeof(tpfile), "%s/%s%s", - webroot, cn->virtualhostreq, fr_str); + snprintf(tpfile, sizeof(tpfile), "/%s%s", + cn->virtualhostreq, fr_str); if (iscgi(tpfile) && isdir(tpfile) == 0) { @@ -782,18 +782,9 @@ static int hexit(char c) return 0; } -static void send404(struct connstruct *cn) -{ - char buf[1024]; - strcpy(buf, "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\n" - "\n404 Not Found

" - "404 Not Found

\n\n"); - special_write(cn, buf, strlen(buf)); -} - static void buildactualfile(struct connstruct *cn) { - snprintf(cn->actualfile, MAXREQUESTLENGTH, "%s%s", webroot, cn->filereq); + snprintf(cn->actualfile, MAXREQUESTLENGTH, "%s", cn->filereq); /* Add directory slash if not there */ if (isdir(cn->actualfile) && @@ -805,9 +796,7 @@ static void buildactualfile(struct connstruct *cn) { char *t = cn->actualfile; while ((t = strchr(t, '/'))) - { *t++ = '\\'; - } } #endif } @@ -855,3 +844,146 @@ static int sanitizehost(char *buf) return 1; } +#ifdef CONFIG_HTTP_HAS_AUTHORIZATION +#define AUTH_FILE ".htpasswd" + +static void send_authenticate(struct connstruct *cn, const char *realm) +{ + char buf[1024]; + + snprintf(buf, sizeof(buf), "HTTP/1.1 401 Unauthorized\n" + "WWW-Authenticate: Basic\n" + "realm=\"%s\"\n", realm); + special_write(cn, buf, strlen(buf)); +} + +static int check_digest(char *b64_file_passwd, const char *msg_passwd) +{ + uint8_t real_salt[MAXREQUESTLENGTH]; + uint8_t real_passwd[MAXREQUESTLENGTH]; + int real_passwd_size, real_salt_size; + char *b64_pwd; + uint8_t md5_result[MD5_SIZE]; + MD5_CTX ctx; + + /* retrieve the salt */ + if ((b64_pwd = strchr(b64_file_passwd, '$')) == NULL) + return -1; + + *b64_pwd++ = 0; + if (base64_decode(b64_file_passwd, strlen(b64_file_passwd), + real_salt, &real_salt_size)) + return -1; + + if (base64_decode(b64_pwd, strlen(b64_pwd), real_passwd, &real_passwd_size)) + return -1; + + /* very simple MD5 crypt algorithm, but then the salt we use is large */ + MD5Init(&ctx); + MD5Update(&ctx, real_salt, real_salt_size); /* process the salt */ + MD5Update(&ctx, msg_passwd, strlen(msg_passwd)); /* process the password */ + MD5Final(&ctx, md5_result); + return memcmp(md5_result, real_passwd, MD5_SIZE);/* 0 = ok */ +} + +static int auth_check(struct connstruct *cn) +{ + char dirname[MAXREQUESTLENGTH]; + char authpath[MAXREQUESTLENGTH]; + char line[MAXREQUESTLENGTH]; + char *cp; + FILE *fp = NULL; + struct stat auth_stat; + + strncpy(dirname, cn->actualfile, MAXREQUESTLENGTH); + cp = strrchr(dirname, '/'); + if (cp == NULL) + dirname[0] = 0; + else + *cp = 0; + + /* check that the file is not the AUTH_FILE itself */ + if (strcmp(cn->actualfile, AUTH_FILE) == 0) + { + send_error(cn, 403); + goto error; + } + + snprintf(authpath, MAXREQUESTLENGTH, "%s/%s", dirname, AUTH_FILE); + if (stat(authpath, &auth_stat) < 0) /* no auth file, so let though */ + return 0; + + if (cn->authorization[0] == 0) + { + send_authenticate(cn, dirname); + return -1; + } + + /* cn->authorization is in form "username:password" */ + if ((cp = strchr(cn->authorization, ':')) == NULL) + goto error; + else + *cp++ = 0; /* cp becomes the password */ + + fp = fopen(authpath, "r"); + + while (fgets(line, sizeof(line), fp) != NULL) + { + char *b64_file_passwd; + int l = strlen(line); + + /* nuke newline */ + if (line[l-1] == '\n') + line[l-1] = 0; + + /* line is form "username:salt(b64)$password(b64)" */ + if ((b64_file_passwd = strchr(line, ':')) == NULL) + continue; + + *b64_file_passwd++ = 0; + + if (strcmp(line, cn->authorization)) /* our user? */ + continue; + + if (check_digest(b64_file_passwd, cp) == 0) + { + fclose(fp); + return 0; + } + } + + fclose(fp); + +error: + send_authenticate(cn, dirname); + return -1; +} +#endif + +static void send_error(struct connstruct *cn, int err) +{ + char buf[1024]; + char *title; + char *text; + + switch (err) + { + case 403: + title = "Forbidden"; + text = "File is protected"; + break; + + case 404: + title = "Not Found"; + text = title; + break; + } + + sprintf(buf, "HTTP/1.1 %d %s\nContent-Type: text/html\n" + "\n%d %s" + "

%d %s

\n\n", + err, title, err, title, err, text); + special_write(cn, buf, strlen(buf)); + removeconnection(cn); +} + diff --git a/samples/c/axssl.c b/samples/c/axssl.c index 7a4e1dd18..6dd794d67 100644 --- a/samples/c/axssl.c +++ b/samples/c/axssl.c @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) WSADATA wsaData; WORD wVersionRequested = MAKEWORD(2, 2); WSAStartup(wVersionRequested, &wsaData); -#elif !defined(SOLARIS) +#elif !defined(CONFIG_PLATFORM_SOLARIS) signal(SIGPIPE, SIG_IGN); /* ignore pipe errors */ #endif diff --git a/ssl/aes.c b/ssl/aes.c index 20922a46c..520bd01a9 100644 --- a/ssl/aes.c +++ b/ssl/aes.c @@ -62,10 +62,6 @@ (f8)^=rot2(f4), \ (f8)^rot1(f9)) -/* some macros to do endian independent byte extraction */ -#define n2l(c,l) l=ntohl(*c); c++ -#define l2n(l,c) *c++=htonl(l) - /* * AES S-box */ @@ -249,7 +245,7 @@ void AES_convert_key(AES_CTX *ctx) k = ctx->ks; k += 4; - for (i=ctx->rounds*4; i>4; i--) + for (i= ctx->rounds*4; i > 4; i--) { w= *k; w = inv_mix_col(w,t1,t2,t3,t4); @@ -262,46 +258,38 @@ void AES_convert_key(AES_CTX *ctx) */ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) { - uint32_t tin0, tin1, tin2, tin3; - uint32_t tout0, tout1, tout2, tout3; - uint32_t tin[4]; - uint32_t *iv = (uint32_t *)ctx->iv; - uint32_t *msg_32 = (uint32_t *)msg; - uint32_t *out_32 = (uint32_t *)out; + int i; + uint32_t tin[4], tout[4], iv[4]; - n2l(iv, tout0); - n2l(iv, tout1); - n2l(iv, tout2); - n2l(iv, tout3); - iv -= 4; + memcpy(iv, ctx->iv, AES_IV_SIZE); + for (i = 0; i < 4; i++) + tout[i] = ntohl(iv[i]); - for (length -= 16; length >= 0; length -= 16) + for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE) { - n2l(msg_32, tin0); - n2l(msg_32, tin1); - n2l(msg_32, tin2); - n2l(msg_32, tin3); - tin[0] = tin0^tout0; - tin[1] = tin1^tout1; - tin[2] = tin2^tout2; - tin[3] = tin3^tout3; + uint32_t msg_32[4]; + uint32_t out_32[4]; + memcpy(msg_32, msg, AES_BLOCKSIZE); + msg += AES_BLOCKSIZE; + + for (i = 0; i < 4; i++) + tin[i] = ntohl(msg_32[i])^tout[i]; AES_encrypt(ctx, tin); - tout0 = tin[0]; - l2n(tout0, out_32); - tout1 = tin[1]; - l2n(tout1, out_32); - tout2 = tin[2]; - l2n(tout2, out_32); - tout3 = tin[3]; - l2n(tout3, out_32); + for (i = 0; i < 4; i++) + { + tout[i] = tin[i]; + out_32[i] = htonl(tout[i]); + } + + memcpy(out, out_32, AES_BLOCKSIZE); + out += AES_BLOCKSIZE; } - l2n(tout0, iv); - l2n(tout1, iv); - l2n(tout2, iv); - l2n(tout3, iv); + for (i = 0; i < 4; i++) + iv[i] = htonl(tout[i]); + memcpy(ctx->iv, iv, AES_IV_SIZE); } /** @@ -309,54 +297,42 @@ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) */ void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) { - uint32_t tin0, tin1, tin2, tin3; - uint32_t xor0,xor1,xor2,xor3; - uint32_t tout0,tout1,tout2,tout3; - uint32_t data[4]; - uint32_t *iv = (uint32_t *)ctx->iv; - uint32_t *msg_32 = (uint32_t *)msg; - uint32_t *out_32 = (uint32_t *)out; + int i; + uint32_t tin[4], xor[4], tout[4], data[4], iv[4]; - n2l(iv ,xor0); - n2l(iv, xor1); - n2l(iv, xor2); - n2l(iv, xor3); - iv -= 4; + memcpy(iv, ctx->iv, AES_IV_SIZE); + for (i = 0; i < 4; i++) + xor[i] = ntohl(iv[i]); - for (length-=16; length >= 0; length -= 16) + for (length -= 16; length >= 0; length -= 16) { - n2l(msg_32, tin0); - n2l(msg_32, tin1); - n2l(msg_32, tin2); - n2l(msg_32, tin3); + uint32_t msg_32[4]; + uint32_t out_32[4]; + memcpy(msg_32, msg, AES_BLOCKSIZE); + msg += AES_BLOCKSIZE; - data[0] = tin0; - data[1] = tin1; - data[2] = tin2; - data[3] = tin3; + for (i = 0; i < 4; i++) + { + tin[i] = ntohl(msg_32[i]); + data[i] = tin[i]; + } AES_decrypt(ctx, data); - tout0 = data[0]^xor0; - tout1 = data[1]^xor1; - tout2 = data[2]^xor2; - tout3 = data[3]^xor3; + for (i = 0; i < 4; i++) + { + tout[i] = data[i]^xor[i]; + xor[i] = tin[i]; + out_32[i] = htonl(tout[i]); + } - xor0 = tin0; - xor1 = tin1; - xor2 = tin2; - xor3 = tin3; - - l2n(tout0, out_32); - l2n(tout1, out_32); - l2n(tout2, out_32); - l2n(tout3, out_32); + memcpy(out, out_32, AES_BLOCKSIZE); + out += AES_BLOCKSIZE; } - l2n(xor0, iv); - l2n(xor1, iv); - l2n(xor2, iv); - l2n(xor3, iv); + for (i = 0; i < 4; i++) + iv[i] = htonl(xor[i]); + memcpy(ctx->iv, iv, AES_IV_SIZE); } /** @@ -375,9 +351,7 @@ static void AES_encrypt(const AES_CTX *ctx, uint32_t *data) /* Pre-round key addition */ for (row = 0; row < 4; row++) - { data[row] ^= *(k++); - } /* Encrypt one block. */ for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++) @@ -395,7 +369,6 @@ static void AES_encrypt(const AES_CTX *ctx, uint32_t *data) { tmp1 = a0 ^ a1 ^ a2 ^ a3; old_a0 = a0; - a0 ^= tmp1 ^ AES_xtime(a0 ^ a1); a1 ^= tmp1 ^ AES_xtime(a1 ^ a2); a2 ^= tmp1 ^ AES_xtime(a2 ^ a3); @@ -408,9 +381,7 @@ static void AES_encrypt(const AES_CTX *ctx, uint32_t *data) /* KeyAddition - note that it is vital that this loop is separate from the MixColumn operation, which must be atomic...*/ for (row = 0; row < 4; row++) - { data[row] = tmp[row] ^ *(k++); - } } } @@ -424,16 +395,14 @@ static void AES_decrypt(const AES_CTX *ctx, uint32_t *data) uint32_t a0, a1, a2, a3, row; int curr_rnd; int rounds = ctx->rounds; - uint32_t *k = (uint32_t*)ctx->ks + ((rounds+1)*4); + const uint32_t *k = ctx->ks + ((rounds+1)*4); /* pre-round key addition */ for (row=4; row > 0;row--) - { data[row-1] ^= *(--k); - } /* Decrypt one block */ - for (curr_rnd=0; curr_rnd < rounds; curr_rnd++) + for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++) { /* Perform ByteSub and ShiftRow operations together */ for (row = 4; row > 0; row--) @@ -468,9 +437,7 @@ static void AES_decrypt(const AES_CTX *ctx, uint32_t *data) } for (row = 4; row > 0; row--) - { data[row-1] = tmp[row-1] ^ *(--k); - } } } diff --git a/ssl/crypto.h b/ssl/crypto.h index ab43972a5..23029f9a6 100644 --- a/ssl/crypto.h +++ b/ssl/crypto.h @@ -34,13 +34,15 @@ extern "C" { **************************************************************************/ #define AES_MAXROUNDS 14 +#define AES_BLOCKSIZE 16 +#define AES_IV_SIZE 16 typedef struct aes_key_st { uint16_t rounds; uint16_t key_size; uint32_t ks[(AES_MAXROUNDS+1)*8]; - uint8_t iv[16]; + uint8_t iv[AES_IV_SIZE]; } AES_CTX; typedef enum @@ -106,9 +108,9 @@ typedef struct uint8_t buffer[64]; /* input buffer */ } MD5_CTX; -void MD5Init(MD5_CTX *); -void MD5Update(MD5_CTX *, const uint8_t *msg, int len); -void MD5Final(MD5_CTX *, uint8_t *digest); +EXP_FUNC void STDCALL MD5Init(MD5_CTX *); +EXP_FUNC void STDCALL MD5Update(MD5_CTX *, const uint8_t *msg, int len); +EXP_FUNC void STDCALL MD5Final(MD5_CTX *, uint8_t *digest); /************************************************************************** * HMAC declarations @@ -273,6 +275,9 @@ void print_blob(const char *format, const uint8_t *data, int size, ...); #define print_blob(...) #endif +EXP_FUNC int STDCALL base64_decode(const char *in, int len, + uint8_t *out, int *outlen); + #ifdef __cplusplus } #endif diff --git a/ssl/crypto_misc.c b/ssl/crypto_misc.c index 030ed650c..8eded5af9 100644 --- a/ssl/crypto_misc.c +++ b/ssl/crypto_misc.c @@ -267,3 +267,78 @@ void print_blob(const char *format, void print_blob(const char *format, const unsigned char *data, int size, ...) {} #endif + +#if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION) +/* base64 to binary lookup table */ +static const uint8_t map[128] = +{ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255 +}; + +EXP_FUNC int STDCALL base64_decode(const char *in, int len, + uint8_t *out, int *outlen) +{ + int g, t, x, y, z; + uint8_t c; + int ret = -1; + + g = 3; + for (x = y = z = t = 0; x < len; x++) + { + if ((c = map[in[x]&0x7F]) == 0xff) + continue; + + if (c == 254) /* this is the end... */ + { + c = 0; + + if (--g < 0) + goto error; + } + else if (g != 3) /* only allow = at end */ + goto error; + + t = (t<<6) | c; + + if (++y == 4) + { + 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; + } + } + + if (y != 0) + goto error; + + if (outlen) + *outlen = z; + ret = 0; + +error: +#ifdef CONFIG_SSL_FULL_MODE + if (ret < 0) + printf("Error: Invalid base64\n"); TTY_FLUSH(); +#endif + TTY_FLUSH(); + return ret; + +} +#endif + diff --git a/ssl/loader.c b/ssl/loader.c index 1bc966515..dd7d17234 100644 --- a/ssl/loader.c +++ b/ssl/loader.c @@ -169,22 +169,6 @@ void ssl_obj_free(SSLObjLoader *ssl_obj) #define IS_ENCRYPTED_PRIVATE_KEY 1 #define IS_CERTIFICATE 2 -/* base64 to binary lookup table */ -static const uint8_t map[128] = -{ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, - 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, - 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 255, 255, 255, 255, 255 -}; - static const char * const begins[NUM_PEM_TYPES] = { "-----BEGIN RSA PRIVATE KEY-----", @@ -205,59 +189,6 @@ static const char * const aes_str[2] = "DEK-Info: AES-256-CBC," }; -static int base64_decode(const uint8_t *in, int len, - uint8_t *out, int *outlen) -{ - int g, t, x, y, z; - uint8_t c; - int ret = -1; - - g = 3; - for (x = y = z = t = 0; x < len; x++) - { - if ((c = map[in[x] & 0x7F]) == 0xff) - continue; - - if (c == 254) /* this is the end... */ - { - c = 0; - - if (--g < 0) - goto error; - } - else if (g != 3) /* only allow = at end */ - goto error; - - t = (t<<6) | c; - - if (++y == 4) - { - 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; - } - } - - if (y != 0) - goto error; - - *outlen = z; - ret = 0; - -error: -#ifdef CONFIG_SSL_FULL_MODE - if (ret < 0) - printf("Error: Invalid base64 file\n"); -#endif - return ret; -} - /** * Take a base64 blob of data and decrypt it (using AES) into its * proper ASN.1 form. @@ -372,7 +303,7 @@ static int new_pem_obj(SSLCTX *ssl_ctx, int is_cacert, uint8_t *where, strstr((const char *)start, "4,ENCRYPTED")) { /* check for encrypted PEM file */ - if ((pem_size = pem_decrypt(start, end, password, ssl_obj)) < 0) + if (pem_decrypt(start, end, password, ssl_obj) < 0) goto error; } else if (base64_decode(start, pem_size, diff --git a/ssl/md5.c b/ssl/md5.c index 704ba05f8..39272d998 100644 --- a/ssl/md5.c +++ b/ssl/md5.c @@ -90,7 +90,7 @@ static const uint8_t PADDING[64] = /** * MD5 initialization - begins an MD5 operation, writing a new ctx. */ -void MD5Init(MD5_CTX *ctx) +EXP_FUNC void STDCALL MD5Init(MD5_CTX *ctx) { ctx->count[0] = ctx->count[1] = 0; @@ -105,7 +105,7 @@ void MD5Init(MD5_CTX *ctx) /** * Accepts an array of octets as the next portion of the message. */ -void MD5Update(MD5_CTX *ctx, const uint8_t * msg, int len) +EXP_FUNC void STDCALL MD5Update(MD5_CTX *ctx, const uint8_t * msg, int len) { uint32_t x; int i, partLen; @@ -141,7 +141,7 @@ void MD5Update(MD5_CTX *ctx, const uint8_t * msg, int len) /** * Return the 128-bit message digest into the user's array */ -void MD5Final(MD5_CTX *ctx, uint8_t *digest) +EXP_FUNC void STDCALL MD5Final(MD5_CTX *ctx, uint8_t *digest) { uint8_t bits[8]; uint32_t x, padLen; diff --git a/ssl/os_port.h b/ssl/os_port.h index fd9f83929..89eeb6b16 100644 --- a/ssl/os_port.h +++ b/ssl/os_port.h @@ -29,7 +29,7 @@ extern "C" { #endif -#if defined(WIN32) || defined(CYGWIN) +#if defined(WIN32) || defined(CONFIG_PLATFORM_CYGWIN) #define STDCALL __stdcall #define EXP_FUNC __declspec(dllexport) #else @@ -56,6 +56,7 @@ extern "C" { #endif /* _WIN32_WCE */ #include +#include #undef getpid #undef open #undef close @@ -81,6 +82,7 @@ extern "C" { #define usleep(A) Sleep(A/1000) #define lseek(A,B,C) _lseek(A,B,C) #define strdup(A) _strdup(A) +#define chroot(A) _chdir(A) /* This fix gets around a problem where a win32 application on a cygwin xterm doesn't display regular output (until a certain buffer limit) - but it works @@ -113,7 +115,7 @@ extern EXP_FUNC int strcasecmp(const char *s1, const char *s2); #else /* Not Win32 */ -#ifdef SOLARIS +#ifdef CONFIG_PLATFORM_SOLARIS #include #else #include diff --git a/ssl/tls1.c b/ssl/tls1.c index e2e9c41ef..ccd28df87 100644 --- a/ssl/tls1.c +++ b/ssl/tls1.c @@ -1123,6 +1123,7 @@ static void set_key_block(SSL *ssl, int is_write) /* clean up if possible */ if (key_block_existed) { + memset(ssl->key_block, 0, ciph_info->key_block_size); free(ssl->key_block); ssl->key_block = NULL; } @@ -1454,9 +1455,11 @@ int process_finished(SSL *ssl, int hs_len) ssl->all_pkts = NULL; ssl->all_pkts_len = 0; + memset(ssl->master_secret, 0, SSL_SECRET_SIZE); free(ssl->master_secret); ssl->master_secret = NULL; + memset(ssl->final_finish_mac, 0, SSL_FINISHED_HASH_SIZE); free(ssl->final_finish_mac); ssl->final_finish_mac = NULL;