diff --git a/httpd/Makefile b/httpd/Makefile index 1b57b3c80..a6023e776 100644 --- a/httpd/Makefile +++ b/httpd/Makefile @@ -57,7 +57,6 @@ OBJ= \ conn.o \ main.o \ proc.o \ - misc.o \ mime_types.o ifndef CONFIG_PLATFORM_WIN32 @@ -71,6 +70,10 @@ endif endif else # Win32 +OBJ:=$(OBJ:.o=.obj) +%.obj : %.c + $(CC) $(CFLAGS) $< + $(TARGET): $(OBJ) $(LD) $(LDFLAGS) $(LIBS) /out:$@ $(OBJ) endif diff --git a/httpd/README b/httpd/README index cb42bfd66..ba11528b0 100644 --- a/httpd/README +++ b/httpd/README @@ -1,6 +1,6 @@ -axhttpd is a small embedded web server using the axTLS library. +axhttpd is a small embedded web server using the axTLS library. -It is based quite closely on the web server written by Doug Currie (original -version is here: http://www.hcsw.org/awhttpd). +It is based originally on the web server written by Doug Currie and is at: +http://www.hcsw.org/awhttpd). diff --git a/httpd/axhttp.h b/httpd/axhttp.h index d4e62f616..06057d215 100644 --- a/httpd/axhttp.h +++ b/httpd/axhttp.h @@ -74,9 +74,9 @@ struct connstruct int numbytes; char databuf[BLOCKSIZE]; - unsigned char is_ssl; - unsigned char close_when_done; - unsigned char modified_since; + uint8_t is_ssl; + uint8_t close_when_done; + uint8_t modified_since; }; struct serverstruct @@ -95,12 +95,6 @@ struct cgiextstruct }; #endif -struct indexstruct -{ - struct indexstruct *next; - char *name; -}; - // Global prototypes extern struct serverstruct *servers; extern struct connstruct *usedconns; @@ -108,49 +102,25 @@ extern struct connstruct *freeconns; #if defined(CONFIG_HTTP_HAS_CGI) extern struct cgiextstruct *cgiexts; #endif -extern struct indexstruct *indexlist; // Conf global prototypes extern char *webroot; -extern int allowdirectorylisting; -extern int allowcgi; -extern int permcheck; // conn.c prototypes void addconnection(int sd, char *ip, int is_ssl); void removeconnection(struct connstruct *cn); // proc.c prototypes -int procheadelem(struct connstruct *cn, char *buf); -void procdirlisting(struct connstruct *cn); void procdodir(struct connstruct *cn); void procreadhead(struct connstruct *cn); void procsendhead(struct connstruct *cn); void procreadfile(struct connstruct *cn); void procsendfile(struct connstruct *cn); -int special_write(struct connstruct *cn, const uint8_t *buf, size_t count); // misc.c prototypes -void nada(int sigtype); -void die(int sigtype); -void reaper(int sigtype); -void stripcrlf(char *p); char *my_strncpy(char *dest, const char *src, size_t n); -#ifndef __HAVE_ARCH_STRNLEN -size_t strnlen ( const char * str, size_t maxlen ); -#endif -int iscgi(char *fn); -void split(char *tp, char *sp[], int maxwords, char sc); -int sanitizefile(char *buf); -int sanitizehost(char *buf); -void buildactualfile(struct connstruct *cn); -int issockwriteable(int sd); -int isdir(char *name); -int trycgi_withpathinfo(struct connstruct *cn); +int isdir(const char *name); // mime_types.c prototypes void mime_init(void); const char *getmimetype(const char *fn); - -// main.c prototypes -void initlists(void); diff --git a/httpd/conn.c b/httpd/conn.c index a36271709..2cbffec2d 100644 --- a/httpd/conn.c +++ b/httpd/conn.c @@ -27,9 +27,7 @@ void addconnection(int sd, char *ip, int is_ssl) // Get ourselves a connstruct if (freeconns == NULL) - { - tp = (struct connstruct *) malloc(sizeof(struct connstruct)); - } + tp = (struct connstruct *)malloc(sizeof(struct connstruct)); else { tp = freeconns; @@ -39,23 +37,21 @@ void addconnection(int sd, char *ip, int is_ssl) // Attach it to the used list tp->next = usedconns; usedconns = tp; - tp->networkdesc = sd; + if (is_ssl) ssl_server_new(servers->ssl_ctx, sd); + tp->is_ssl = is_ssl; tp->filedesc = -1; #if defined(CONFIG_HTTP_HAS_DIRECTORIES) tp->dirp = NULL; #endif - tp->is_ssl = is_ssl; - *(tp->actualfile) = '\0'; *(tp->filereq) = '\0'; #if defined(CONFIG_HTTP_HAS_CGI) *(tp->cgiargs) = '\0'; #endif *(tp->virtualhostreq) = '\0'; - tp->state = STATE_WANT_TO_READ_HEAD; tp->reqtype = TYPE_GET; my_strncpy(tp->ip, ip, MAXIPLEN); @@ -67,27 +63,27 @@ void addconnection(int sd, char *ip, int is_ssl) void removeconnection(struct connstruct *cn) { struct connstruct *tp; - int shouldret=0; + int shouldret = 0; tp = usedconns; if (tp == NULL || cn == NULL) - shouldret=1; + shouldret = 1; else if (tp == cn) usedconns = tp->next; else { - while(tp != NULL) + while (tp != NULL) { if (tp->next == cn) { tp->next = (tp->next)->next; - shouldret=0; + shouldret = 0; break; } tp = tp->next; - shouldret=1; + shouldret = 1; } } @@ -102,14 +98,14 @@ void removeconnection(struct connstruct *cn) if (cn->networkdesc != -1) { if (cn->is_ssl) - { ssl_free(ssl_find(servers->ssl_ctx, cn->networkdesc)); - } SOCKET_CLOSE(cn->networkdesc); } - if (cn->filedesc != -1) close(cn->filedesc); + if (cn->filedesc != -1) + close(cn->filedesc); + #if defined(CONFIG_HTTP_HAS_DIRECTORIES) if (cn->dirp != NULL) #ifdef WIN32 diff --git a/httpd/main.c b/httpd/main.c index 8254d3c54..da2608652 100644 --- a/httpd/main.c +++ b/httpd/main.c @@ -27,23 +27,25 @@ struct serverstruct *servers; struct connstruct *usedconns; struct connstruct *freeconns; -#if defined(CONFIG_HTTP_HAS_CGI) -struct cgiextstruct *cgiexts; -#endif -struct indexstruct *indexlist; - char *webroot = CONFIG_HTTP_WEBROOT; -static void addindex(char *tp); static void addtoservers(int sd); -static void selectloop(void); static int openlistener(int port); static void handlenewconnection(int listenfd, int is_ssl); #if defined(CONFIG_HTTP_PERM_CHECK) -static void procpermcheck(char *pathtocheck); +static void procpermcheck(const char *pathtocheck); #endif + #if defined(CONFIG_HTTP_HAS_CGI) +struct cgiextstruct *cgiexts; static void addcgiext(char *tp); + +#if !defined(WIN32) +static void reaper(int sigtype) +{ + wait3(NULL, WNOHANG, NULL); +} +#endif #endif /* clean up memory for valgrind */ @@ -53,7 +55,7 @@ static void sigint_cleanup(int sig) struct connstruct *tp; int i; - while(servers != NULL) + while (servers != NULL) { if (servers->is_ssl) ssl_ctx_free(servers->ssl_ctx); @@ -63,9 +65,6 @@ static void sigint_cleanup(int sig) servers = sp; } - free(indexlist->name); - free(indexlist); - for (i = 0; i < INITIAL_CONNECTION_SLOTS; i++) { if (freeconns == NULL) @@ -79,46 +78,52 @@ static void sigint_cleanup(int sig) exit(0); } -void initlists() +static void die(int sigtype) { - int i; - struct connstruct *tp; - - servers = NULL; - usedconns = NULL; - freeconns = NULL; -#if defined(CONFIG_HTTP_HAS_CGI) - cgiexts = NULL; -#endif - indexlist = NULL; - - for (i=0; inext = tp; - } + exit(0); } int main(int argc, char *argv[]) { - int tp; -#if defined(CONFIG_HTTP_IS_DAEMON) - int pid; -#endif + fd_set rfds, wfds; + struct connstruct *tp, *to; + struct serverstruct *sp; + int rnum, wnum, active; + int webrootlen, i; + time_t currtime; #ifdef WIN32 - WORD wVersionRequested = MAKEWORD(2,2); + WORD wVersionRequested = MAKEWORD(2, 2); 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) + signal(SIGCHLD, reaper); #endif - +#endif + signal(SIGINT, sigint_cleanup); + signal(SIGTERM, die); mime_init(); - initlists(); - tp = strlen(webroot); - if (webroot[tp-1] == '/') - webroot[tp-1] = '\0'; + for (i = 0; i < INITIAL_CONNECTION_SLOTS; i++) + { + tp = freeconns; + freeconns = (struct connstruct *)calloc(1, sizeof(struct connstruct)); + freeconns->next = tp; + } + + webrootlen = strlen(webroot); + + if (webroot[webrootlen-1] == '/') + webroot[webrootlen-1] = '\0'; if (isdir(webroot) == 0) { @@ -128,38 +133,29 @@ int main(int argc, char *argv[]) exit(1); } - if ((tp = openlistener(CONFIG_HTTP_PORT)) == -1) + if ((active = openlistener(CONFIG_HTTP_PORT)) == -1) { #ifdef CONFIG_HTTP_VERBOSE - fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n", + fprintf(stderr, "ERR: Couldn't bind to port %d\n", CONFIG_HTTP_PORT); #endif exit(1); } - addindex("index.html"); - addtoservers(tp); + addtoservers(active); -#ifndef WIN32 - if (getuid() == 0) - { - setgid(32767); - setuid(32767); - } -#endif - - if ((tp = openlistener(CONFIG_HTTP_HTTPS_PORT)) == -1) + if ((active = openlistener(CONFIG_HTTP_HTTPS_PORT)) == -1) { #ifdef CONFIG_HTTP_VERBOSE - fprintf(stderr, "ERR: Couldn't bind to port %d (IPv4)\n", + fprintf(stderr, "ERR: Couldn't bind to port %d\n", CONFIG_HTTP_HTTPS_PORT); #endif exit(1); } - addtoservers(tp); + addtoservers(active); servers->ssl_ctx = ssl_ctx_new(CONFIG_HTTP_DEFAULT_SSL_OPTIONS, - CONFIG_HTTP_SESSION_CACHE_SIZE); + CONFIG_HTTP_SESSION_CACHE_SIZE); servers->is_ssl = 1; #if defined(CONFIG_HTTP_PERM_CHECK) @@ -173,53 +169,152 @@ int main(int argc, char *argv[]) CONFIG_HTTP_PORT, CONFIG_HTTP_HTTPS_PORT); TTY_FLUSH(); #endif - #if defined(CONFIG_HTTP_IS_DAEMON) - pid = fork(); - - if (pid > 0) - { + if (fork() > 0) /* parent will die */ exit(0); - } - else if(pid == -1) - { -#ifdef CONFIG_HTTP_VERBOSE - fprintf(stderr,"axhttpd: Sorry, fork failed... Tough dice.\n"); -#endif - exit(1); - } setsid(); #endif - /* SIGNALS */ - signal(SIGINT, sigint_cleanup); - signal(SIGTERM, die); -#if defined(CONFIG_HTTP_HAS_CGI) -#ifndef WIN32 - signal(SIGCHLD, reaper); -#endif -#endif -#ifndef WIN32 - signal(SIGQUIT, die); - signal(SIGPIPE, SIG_IGN); -#endif + // main loop + while (1) + { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + rnum = wnum = -1; + sp = servers; + + while (sp != NULL) // read each server port + { + FD_SET(sp->sd, &rfds); + + if (sp->sd > rnum) + rnum = sp->sd; + sp = sp->next; + } + + // Add the established sockets + tp = usedconns; + currtime = time(NULL); + + while (tp != NULL) + { + if (currtime > tp->timeout) // timed out? Kill it. + { + to = tp; + tp = tp->next; + removeconnection(to); + continue; + } + + if (tp->state == STATE_WANT_TO_READ_HEAD) + { + FD_SET(tp->networkdesc, &rfds); + if (tp->networkdesc > rnum) + rnum = tp->networkdesc; + } + + if (tp->state == STATE_WANT_TO_SEND_HEAD) + { + FD_SET(tp->networkdesc, &wfds); + if (tp->networkdesc > wnum) + wnum = tp->networkdesc; + } + + if (tp->state == STATE_WANT_TO_READ_FILE) + { + FD_SET(tp->filedesc, &rfds); + if (tp->filedesc > rnum) + rnum = tp->filedesc; + } + + if (tp->state == STATE_WANT_TO_SEND_FILE) + { + FD_SET(tp->networkdesc, &wfds); + if (tp->networkdesc > wnum) + wnum = tp->networkdesc; + } + +#if defined(CONFIG_HTTP_DIRECTORIES) + if (tp->state == STATE_DOING_DIR) + { + FD_SET(tp->networkdesc, &wfds); + if (tp->networkdesc > wnum) + wnum = tp->networkdesc; + } +#endif + tp = tp->next; + } + + active = select(wnum > rnum ? wnum+1 : rnum+1, + rnum != -1 ? &rfds : NULL, wnum != -1 ? &wfds : NULL, + NULL, NULL); + + // New connection? + sp = servers; + while (active > 0 && sp != NULL) + { + if (FD_ISSET(sp->sd, &rfds)) + { + handlenewconnection(sp->sd, sp->is_ssl); + active--; + } + + sp = sp->next; + } + + // Handle the established sockets + tp = usedconns; + + while (active > 0 && tp != NULL) + { + to = tp; + tp = tp->next; + + if (to->state == STATE_WANT_TO_READ_HEAD) + if (FD_ISSET(to->networkdesc, &rfds)) + { + active--; + procreadhead(to); + } + + if (to->state == STATE_WANT_TO_SEND_HEAD) + if (FD_ISSET(to->networkdesc, &wfds)) + { + active--; + procsendhead(to); + } + + if (to->state == STATE_WANT_TO_READ_FILE) + if (FD_ISSET(to->filedesc, &rfds)) + { + active--; + procreadfile(to); + } + + if (to->state == STATE_WANT_TO_SEND_FILE) + if (FD_ISSET(to->networkdesc, &wfds)) + { + active--; + procsendfile(to); + } + +#if defined(CONFIG_HTTP_DIRECTORIES) + if (to->state == STATE_DOING_DIR) + if (FD_ISSET(to->networkdesc, &wfds)) + { + active--; + procdodir(to); + } +#endif + } + } - selectloop(); return 0; } -static void addindex(char *tp) -{ - struct indexstruct *ex = (struct indexstruct *) - malloc(sizeof(struct indexstruct)); - ex->name = strdup(tp); - ex->next = indexlist; - indexlist = ex; -} - #if defined(CONFIG_HTTP_PERM_CHECK) -static void procpermcheck(char *pathtocheck) +static void procpermcheck(const char *pathtocheck) { char thepath[MAXREQUESTLENGTH]; #ifndef WIN32 @@ -232,31 +327,35 @@ static void procpermcheck(char *pathtocheck) { printf("WARNING: UID (%d) is unable to read %s\n", (int)getuid(), pathtocheck); + TTY_FLUSH(); return; } - while ((dp=readdir(tpdir))) + while ((dp = readdir(tpdir))) { - if (strcmp(dp->d_name, "..")==0) + if (strcmp(dp->d_name, "..") == 0) continue; - if (strcmp(dp->d_name, ".")==0) + if (strcmp(dp->d_name, ".") == 0) continue; snprintf(thepath, sizeof(thepath), "%s/%s", pathtocheck, dp->d_name); - if (isdir(thepath)) + if (isdir(thepath)) { procpermcheck(thepath); continue; } if (access(thepath, R_OK) != 0) - printf("WARNING: UID (%d) is unable to read %s\n", + printf("WARNING: UID (%d) is unable to read %s\n", (int)getuid(), thepath); + if (access(thepath, W_OK) == 0) - printf("SECURITY: UID (%d) is ABLE TO WRITE TO %s\n", + printf("SECURITY: UID (%d) is ABLE TO WRITE TO %s\n", (int)getuid(), thepath); + + TTY_FLUSH(); } closedir(tpdir); @@ -335,149 +434,6 @@ static void addtoservers(int sd) servers = tp; } -static void selectloop(void) -{ - fd_set rfds, wfds; - struct connstruct *tp, *to; - struct serverstruct *sp; - int rnum, wnum, active; - int currtime; - - while (1) - { - // MAIN SELECT LOOP - FD_ZERO(&rfds); - FD_ZERO(&wfds); - rnum = wnum = -1; - - // Add the listening sockets - sp = servers; - while (sp != NULL) - { - FD_SET(sp->sd, &rfds); - if (sp->sd > rnum) rnum = sp->sd; - sp = sp->next; - } - - // Add the established sockets - tp = usedconns; - currtime = time(NULL); - - while (tp != NULL) - { - if (currtime > tp->timeout) - { - to = tp; - tp = tp->next; - removeconnection(to); - continue; - } - - if (tp->state == STATE_WANT_TO_READ_HEAD) - { - FD_SET(tp->networkdesc, &rfds); - if (tp->networkdesc > rnum) - rnum = tp->networkdesc; - } - - if (tp->state == STATE_WANT_TO_SEND_HEAD) - { - FD_SET(tp->networkdesc, &wfds); - if (tp->networkdesc > wnum) - wnum = tp->networkdesc; - } - - if (tp->state == STATE_WANT_TO_READ_FILE) - { - FD_SET(tp->filedesc, &rfds); - if (tp->filedesc > rnum) - rnum = tp->filedesc; - } - - if (tp->state == STATE_WANT_TO_SEND_FILE) - { - FD_SET(tp->networkdesc, &wfds); - if (tp->networkdesc > wnum) - wnum = tp->networkdesc; - } - -#if defined(CONFIG_HTTP_DIRECTORIES) - if (tp->state == STATE_DOING_DIR) - { - FD_SET(tp->networkdesc, &wfds); - if (tp->networkdesc > wnum) - wnum = tp->networkdesc; - } -#endif - tp = tp->next; - } - - active = select(wnum > rnum ? wnum+1 : rnum+1, - rnum != -1 ? &rfds : NULL, - wnum != -1 ? &wfds : NULL, - NULL, NULL); - - // Handle the listening sockets - sp = servers; - while (active > 0 && sp != NULL) - { - if (FD_ISSET(sp->sd, &rfds)) - { - handlenewconnection(sp->sd, sp->is_ssl); - active--; - } - - sp = sp->next; - } - - // Handle the established sockets - tp = usedconns; - - while (active > 0 && tp != NULL) - { - to = tp; - tp = tp->next; - - if (to->state == STATE_WANT_TO_READ_HEAD) - if (FD_ISSET(to->networkdesc, &rfds)) - { - active--; - procreadhead(to); - } - - if (to->state == STATE_WANT_TO_SEND_HEAD) - if (FD_ISSET(to->networkdesc, &wfds)) - { - active--; - procsendhead(to); - } - - if (to->state == STATE_WANT_TO_READ_FILE) - if (FD_ISSET(to->filedesc, &rfds)) - { - active--; - procreadfile(to); - } - - if (to->state == STATE_WANT_TO_SEND_FILE) - if (FD_ISSET(to->networkdesc, &wfds)) - { - active--; - procsendfile(to); - } - -#if defined(CONFIG_HTTP_DIRECTORIES) - if (to->state == STATE_DOING_DIR) - if (FD_ISSET(to->networkdesc, &wfds)) - { - active--; - procdodir(to); - } -#endif - } - } // MAIN SELECT LOOP -} - #ifdef HAVE_IPV6 static void handlenewconnection(int listenfd, int is_ssl) { @@ -486,9 +442,6 @@ static void handlenewconnection(int listenfd, int is_ssl) char ipbuf[100]; int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp); - if (connfd == -1) - return; - if (tp == sizeof(struct sockaddr_in6)) { inet_ntop(AF_INET6, &their_addr.sin6_addr, ipbuf, sizeof(ipbuf)); @@ -512,10 +465,6 @@ static void handlenewconnection(int listenfd, int is_ssl) struct sockaddr_in their_addr; int tp = sizeof(struct sockaddr_in); int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp); - - if (connfd == -1) - return; - addconnection(connfd, inet_ntoa(their_addr.sin_addr), is_ssl); } #endif @@ -524,62 +473,60 @@ static int openlistener(int port) { int sd; #ifdef WIN32 - char tp=1; + char tp = 1; #else - int tp=1; + int tp = 1; #endif +#ifndef HAVE_IPV6 struct sockaddr_in my_addr; if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) return -1; - setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp)); - my_addr.sin_family = AF_INET; // host byte order - my_addr.sin_port = htons((short)port); // short, network byte order - my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP - memset(&(my_addr.sin_zero), 0, 8); // zero the rest of the struct - - if (bind(sd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) - { - close(sd); - return -1; - } - - if (listen(sd, BACKLOG) == -1) - { - close(sd); - return -1; - } - - return sd; -} - -#ifdef HAVE_IPV6 -static int openlistener6(int port) -{ - int sd,tp; + memset(&my_addr, 0, sizeof(my_addr)); + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons((short)port); + my_addr.sin_addr.s_addr = INADDR_ANY; +#else struct sockaddr_in6 my_addr; if ((sd = socket(AF_INET6, SOCK_STREAM, 0)) == -1) return -1; - setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp)); memset(&my_addr, 0, sizeof(my_addr)); my_addr.sin6_family = AF_INET6; my_addr.sin6_port = htons(port); + my_addr.sin6_addr.s_addr = INADDR_ANY; +#endif - if (bind(sd, (struct sockaddr *)&my_addr, sizeof(my_addr)) == -1) - { - close(sd); - return -1; - } - - if (listen(sd, BACKLOG) == -1) - { - close(sd); - return -1; - } + setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp)); + bind(sd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)); + listen(sd, BACKLOG); return sd; } -#endif + +/* Wrapper function for strncpy() that guarantees + a null-terminated string. This is to avoid any possible + issues due to strncpy()'s behaviour. + */ +char *my_strncpy(char *dest, const char *src, size_t n) +{ + strncpy(dest, src, n); + dest[n-1] = '\0'; + return dest; +} + +int isdir(const char *tpbuf) +{ + struct stat st; + + if (stat(tpbuf, &st) == -1) + return 0; + + if ((st.st_mode & S_IFMT) == S_IFDIR) + return 1; + + return 0; +} + diff --git a/httpd/proc.c b/httpd/proc.c index 88c7fbab6..d4bde5d8c 100644 --- a/httpd/proc.c +++ b/httpd/proc.c @@ -27,21 +27,31 @@ #include "axhttp.h" 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 send301(struct connstruct *cn); static void send404(struct connstruct *cn); static int procindex(struct connstruct *cn, struct stat *stp); static int hexit(char c); static void urldecode(char *buf); +static void buildactualfile(struct connstruct *cn); +static int sanitizefile(const char *buf); +static int sanitizehost(char *buf); #if defined(CONFIG_HTTP_DIRECTORIES) -static void urlencode(unsigned char *s, unsigned char *t); +static void urlencode(const uint8_t *s, uint8_t *t); +static void procdirlisting(struct connstruct *cn); +static int issockwriteable(int sd); #endif #if defined(CONFIG_HTTP_HAS_CGI) static void proccgi(struct connstruct *cn, int has_pathinfo); +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 // Returns 1 if elems should continue being read, 0 otherwise -int procheadelem(struct connstruct *cn, char *buf) +static int procheadelem(struct connstruct *cn, char *buf) { char *delim, *value; #if defined(CONFIG_HTTP_HAS_CGI) @@ -98,7 +108,8 @@ int procheadelem(struct connstruct *cn, char *buf) my_strncpy(cn->virtualhostreq, value, MAXREQUESTLENGTH); } else if (strcmp(buf, "Connection:")==0 && - strcmp(value, "close")==0) { + strcmp(value, "close")==0) + { cn->close_when_done = 1; } else if (strcmp(buf, "If-Modified-Since:") ==0 ) @@ -111,33 +122,26 @@ int procheadelem(struct connstruct *cn, char *buf) } #if defined(CONFIG_HTTP_DIRECTORIES) -void procdirlisting(struct connstruct *cn) +static void procdirlisting(struct connstruct *cn) { char buf[MAXREQUESTLENGTH]; char actualfile[1024]; -#ifndef CONFIG_HTTP_DIRECTORIES - if (allowdirectorylisting == 0) - { - send404(cn); - removeconnection(cn); - return; - } -#endif - if (cn->reqtype == TYPE_HEAD) { - snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nContent-Type: text/html\n\n"); + snprintf(buf, sizeof(buf), + "HTTP/1.1 200 OK\nContent-Type: text/html\n\n"); write(cn->networkdesc, buf, strlen(buf)); - removeconnection(cn); return; } strcpy(actualfile, cn->actualfile); + #ifdef WIN32 strcat(actualfile, "*"); cn->dirp = FindFirstFile(actualfile, &cn->file_data); + if (cn->dirp == INVALID_HANDLE_VALUE) { send404(cn); @@ -145,10 +149,7 @@ void procdirlisting(struct connstruct *cn) return; } #else - - cn->dirp = opendir(actualfile); - - if (cn->dirp == NULL) + if ((cn->dirp = opendir(actualfile)) == NULL) { send404(cn); removeconnection(cn); @@ -159,7 +160,10 @@ void procdirlisting(struct connstruct *cn) readdir(cn->dirp); #endif - sprintf(buf, "HTTP/1.1 200 OK\nContent-Type: text/html\n\n\nDirectory Listing\n

Directory listing of %s://%s%s


\n", cn->is_ssl ? "https" : "http", cn->virtualhostreq, cn->filereq); + snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nContent-Type: text/html\n\n" + "\nDirectory Listing\n" + "

Directory listing of %s://%s%s


\n", + cn->is_ssl ? "https" : "http", cn->virtualhostreq, cn->filereq); special_write(cn, buf, strlen(buf)); cn->state = STATE_DOING_DIR; } @@ -179,14 +183,14 @@ void procdodir(struct connstruct *cn) #ifdef WIN32 if (!FindNextFile(cn->dirp, &cn->file_data)) #else - if ((dp = readdir(cn->dirp)) == NULL) + if ((dp = readdir(cn->dirp)) == NULL) #endif - { - snprintf(buf, sizeof(buf), "\n"); - special_write(cn, buf, strlen(buf)); - removeconnection(cn); - return; - } + { + snprintf(buf, sizeof(buf), "\n"); + special_write(cn, buf, strlen(buf)); + removeconnection(cn); + return; + } #ifdef WIN32 file = cn->file_data.cFileName; @@ -199,31 +203,45 @@ void procdodir(struct connstruct *cn) snprintf(buf, sizeof(buf), "%s%s", cn->actualfile, file); putslash = isdir(buf); - urlencode(file, encbuf); snprintf(buf, sizeof(buf), "%s%s
\n", encbuf, putslash ? "/" : "", file, putslash ? "/" : ""); special_write(cn, buf, strlen(buf)); + } while (issockwriteable(cn->networkdesc)); +} - } - while (issockwriteable(cn->networkdesc)); +static int issockwriteable(int sd) +{ + fd_set wfds; + struct timeval tv; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + FD_ZERO(&wfds); + FD_SET(sd, &wfds); + + select(FD_SETSIZE, NULL, &wfds, NULL, &tv); + return FD_ISSET(sd, &wfds); } /* Encode funny chars -> %xx in newly allocated storage */ /* (preserves '/' !) */ -static void urlencode(unsigned char *s, unsigned char *t) +static void urlencode(const uint8_t *s, uint8_t *t) { - uint8_t *p, *tp; + const uint8_t *p = s; + uint8_t *tp; - tp =t ; + tp = t; - for (p=s; *p; p++) + for (; *p; p++) { if ((*p > 0x00 && *p < ',') || (*p > '9' && *p < 'A') || (*p > 'Z' && *p < '_') || (*p > '_' && *p < 'a') || - (*p > 'z' && *p < 0xA1)) { + (*p > 'z' && *p < 0xA1)) + { sprintf((char *)tp, "%%%02X", *p); tp += 3; } @@ -245,24 +263,23 @@ void procreadhead(struct connstruct *cn) int rv; rv = special_read(cn, buf, sizeof(buf)-1); - if (rv <= 0) { - if (rv < 0) + if (rv <= 0) + { + if (rv < 0) // really dead? removeconnection(cn); return; } buf[rv] = '\0'; - next = tp = buf; // Split up lines and send to procheadelem() - while(*next != '\0') + while (*next != '\0') { // If we have a blank line, advance to next stage! if (*next == '\r' || *next == '\n') { buildactualfile(cn); - cn->state = STATE_WANT_TO_SEND_HEAD; return; } @@ -273,7 +290,7 @@ void procreadhead(struct connstruct *cn) if (*next == '\r') { *next = '\0'; - next+=2; + next += 2; } else if (*next == '\n') *next++ = '\0'; @@ -295,8 +312,8 @@ void procsendhead(struct connstruct *cn) struct stat stbuf; time_t now = cn->timeout - CONFIG_HTTP_TIMEOUT; char date[32]; - strcpy(date, ctime(&now)); + strcpy(date, ctime(&now)); strcpy(actualfile, cn->actualfile); #ifdef WIN32 @@ -309,8 +326,9 @@ void procsendhead(struct connstruct *cn) { #if defined(CONFIG_HTTP_HAS_CGI) if (trycgi_withpathinfo(cn) == 0) - { // We Try To Find A CGI - proccgi(cn,1); + { + // We Try To Find A CGI + proccgi(cn, 1); return; } #endif @@ -321,7 +339,7 @@ void procsendhead(struct connstruct *cn) } #if defined(CONFIG_HTTP_HAS_CGI) - if (iscgi(cn->actualfile)) + if (iscgi(cn->actualfile)) { #ifndef WIN32 // Set up CGI script @@ -333,7 +351,7 @@ void procsendhead(struct connstruct *cn) } #endif - proccgi(cn,0); + proccgi(cn, 0); return; } #endif @@ -362,7 +380,7 @@ 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 (iscgi(cn->actualfile)) + if (iscgi(cn->actualfile)) { // Set up CGI script if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) @@ -372,45 +390,7 @@ void procsendhead(struct connstruct *cn) return; } - proccgi(cn,0); - return; - } -#endif - // If the index isn't a CGI, we continue on with the index file - } - - if ((stbuf.st_mode & S_IFMT) == S_IFDIR) - { - if (cn->filereq[strlen(cn->filereq)-1] != '/') - { - send301(cn); - removeconnection(cn); - return; - } - - // 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 - procdirlisting(cn); -#endif - return; - } - -#if defined(CONFIG_HTTP_HAS_CGI) - // If the index is a CGI file, handle it like any other CGI - if (iscgi(cn->actualfile)) - { - // Set up CGI script - if ((stbuf.st_mode & S_IEXEC) == 0 || isdir(cn->actualfile)) - { - send404(cn); - removeconnection(cn); - return; - } - - proccgi(cn,0); + proccgi(cn, 0); return; } #endif @@ -419,7 +399,8 @@ void procsendhead(struct connstruct *cn) if (cn->modified_since) { - snprintf(buf, sizeof(buf), "HTTP/1.1 304 Not Modified\nServer: axhttpd V%s\nDate: %s\n", VERSION, date); + 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)); cn->modified_since = 0; cn->state = STATE_WANT_TO_READ_HEAD; @@ -433,12 +414,11 @@ void procsendhead(struct connstruct *cn) TTY_FLUSH(); #endif - snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: axhttpd V%s\nContent-Type: %s\nContent-Length: %ld\nDate: %sLast-Modified: %s\n", - VERSION, - getmimetype(cn->actualfile), - (long) stbuf.st_size, - date, - ctime(&(stbuf.st_mtime))); // ctime() has a \n on the end + snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: axhttpd V%s\n" + "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 } special_write(cn, buf, strlen(buf)); @@ -478,7 +458,6 @@ void procsendhead(struct connstruct *cn) #else cn->state = STATE_WANT_TO_READ_FILE; #endif - return; } } @@ -490,10 +469,11 @@ void procreadfile(struct connstruct *cn) { close(cn->filedesc); cn->filedesc = -1; - if (cn->close_when_done) /* close immediately */ + + if (cn->close_when_done) /* close immediately */ removeconnection(cn); else - { /* keep socket open - HTTP 1.1 */ + { /* keep socket open - HTTP 1.1 */ cn->state = STATE_WANT_TO_READ_HEAD; cn->numbytes = 0; } @@ -514,7 +494,9 @@ void procsendfile(struct connstruct *cn) else if (rv == cn->numbytes) cn->state = STATE_WANT_TO_READ_FILE; else if (rv == 0) - { /* Do nothing */ } + { + /* Do nothing */ + } else { memmove(cn->databuf, cn->databuf + rv, cn->numbytes - rv); @@ -522,24 +504,16 @@ void procsendfile(struct connstruct *cn) } } -int special_write(struct connstruct *cn, const uint8_t *buf, size_t count) +static int special_write(struct connstruct *cn, + const uint8_t *buf, size_t count) { - int res; - if (cn->is_ssl) { SSL *ssl = ssl_find(servers->ssl_ctx, cn->networkdesc); - if (ssl) - { - res = ssl_write(ssl, (unsigned char *)buf, count); - } - else - return -1; + return ssl ? ssl_write(ssl, (uint8_t *)buf, count) : -1; } else - res = SOCKET_WRITE(cn->networkdesc, buf, count); - - return res; + return SOCKET_WRITE(cn->networkdesc, buf, count); } static int special_read(struct connstruct *cn, void *buf, size_t count) @@ -549,7 +523,7 @@ 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); - unsigned char *read_buf; + uint8_t *read_buf; if ((res = ssl_read(ssl, &read_buf)) > SSL_OK) memcpy(buf, read_buf, res > (int)count ? count : res); @@ -566,26 +540,12 @@ static int special_read(struct connstruct *cn, void *buf, size_t count) static int procindex(struct connstruct *cn, struct stat *stp) { char tbuf[MAXREQUESTLENGTH]; - struct indexstruct *tp; - tp = indexlist; - - while(tp != NULL) { - sprintf(tbuf, "%s%s%s", cn->actualfile, -#ifdef WIN32 - "\\", -#else - "/", -#endif - tp->name); - - if (stat(tbuf, stp) != -1) - { - my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH); - return 1; - } - - tp = tp->next; + sprintf(tbuf, "%s%s", cn->actualfile, "index.html"); + if (stat(tbuf, stp) != -1) + { + my_strncpy(cn->actualfile, tbuf, MAXREQUESTLENGTH); + return 1; } return 0; @@ -599,8 +559,6 @@ static void proccgi(struct connstruct *cn, int has_pathinfo) char buf[MAXREQUESTLENGTH]; #ifdef WIN32 int tmp_stdout; -#else - int fv; #endif snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\nServer: axhttpd V%s\n%s", @@ -614,28 +572,15 @@ static void proccgi(struct connstruct *cn, int has_pathinfo) } #ifndef WIN32 - if (pipe(tpipe) == -1) - { - removeconnection(cn); - return; - } + pipe(tpipe); - fv = fork(); - - if (fv == -1) - { - close(tpipe[0]); - close(tpipe[1]); - removeconnection(cn); - return; - } - - if (fv != 0) + if (fork() > 0) // parent { // Close the write descriptor close(tpipe[1]); cn->filedesc = tpipe[0]; cn->state = STATE_WANT_TO_READ_FILE; + cn->close_when_done = 1; return; } @@ -653,7 +598,6 @@ static void proccgi(struct connstruct *cn, int has_pathinfo) close(tpipe[0]); close(tpipe[1]); - myargs[0] = cn->actualfile; myargs[1] = cn->cgiargs; myargs[2] = NULL; @@ -666,11 +610,7 @@ static void proccgi(struct connstruct *cn, int has_pathinfo) execv(cn->actualfile, myargs); #else /* WIN32 */ - if (_pipe(tpipe, 4096, O_BINARY| O_NOINHERIT) == -1) - { - removeconnection(cn); - return; - } + _pipe(tpipe, 4096, O_BINARY| O_NOINHERIT); myargs[0] = "sh"; myargs[1] = "-c"; @@ -703,6 +643,7 @@ static void proccgi(struct connstruct *cn, int has_pathinfo) close(tmp_stdout); cn->filedesc = tpipe[0]; cn->state = STATE_WANT_TO_READ_FILE; + cn->close_when_done = 1; for (;;) { @@ -716,6 +657,97 @@ static void proccgi(struct connstruct *cn, int has_pathinfo) } #endif } + +static int trycgi_withpathinfo(struct connstruct *cn) +{ + char tpfile[MAXREQUESTLENGTH]; + char fr_str[MAXREQUESTLENGTH]; + char *fr_rs[MAXCGIARGS]; // filereq splitted + int i = 0, offset; + + my_strncpy(fr_str, cn->filereq, MAXREQUESTLENGTH); + split(fr_str, fr_rs, MAXCGIARGS, '/'); + + while (fr_rs[i] != NULL) + { + snprintf(tpfile, sizeof(tpfile), "%s/%s%s", + webroot, cn->virtualhostreq, fr_str); + + if (iscgi(tpfile) && isdir(tpfile) == 0) + { + /* We've found our CGI file! */ + my_strncpy(cn->actualfile, tpfile, MAXREQUESTLENGTH); + my_strncpy(cn->cgiscriptinfo, fr_str, MAXREQUESTLENGTH); + + offset = (fr_rs[i] + strlen(fr_rs[i])) - fr_str; + my_strncpy(cn->cgipathinfo, cn->filereq+offset, MAXREQUESTLENGTH); + + return 0; + } + + *(fr_rs[i]+strlen(fr_rs[i])) = '/'; + i++; + } + + /* Couldn't find any CGIs :( */ + *(cn->cgiscriptinfo) = '\0'; + *(cn->cgipathinfo) = '\0'; + return -1; +} + +static int iscgi(const char *fn) +{ + struct cgiextstruct *tp; + int fnlen, extlen; + + fnlen = strlen(fn); + tp = cgiexts; + + while (tp != NULL) + { + extlen = strlen(tp->ext); + + if (strcasecmp(fn+(fnlen-extlen), tp->ext) == 0) + return 1; + + tp = tp->next; + } + + return 0; +} + +static void split(char *tp, char *sp[], int maxwords, char sc) +{ + int i = 0; + + while(1) + { + /* Skip leading whitespace */ + while (*tp == sc) tp++; + + if (*tp == '\0') + { + sp[i] = NULL; + break; + } + + if (i==maxwords-2) + { + sp[maxwords-2] = NULL; + break; + } + + sp[i] = tp; + + while(*tp != sc && *tp != '\0') + tp++; + + if (*tp == sc) + *tp++ = '\0'; + + i++; + } +} #endif /* CONFIG_HTTP_HAS_CGI */ /* Decode string %xx -> char (in place) */ @@ -730,26 +762,28 @@ static void urldecode(char *buf) { v = 0; - if (*p=='%') + if (*p == '%') { s = p; s++; if (isxdigit((int) s[0]) && isxdigit((int) s[1])) { - v = hexit(s[0])*16+hexit(s[1]); + v = hexit(s[0])*16 + hexit(s[1]); + if (v) - { /* do not decode %00 to null char */ - *w=(char)v; - p=&s[1]; + { + /* do not decode %00 to null char */ + *w = (char)v; + p = &s[1]; } } } - if (!v) - *w=*p; - p++; w++; + if (!v) *w=*p; + p++; + w++; } *w='\0'; @@ -757,27 +791,98 @@ static void urldecode(char *buf) static int hexit(char c) { - if ( c >= '0' && c <= '9' ) + if (c >= '0' && c <= '9') return c - '0'; - if ( c >= 'a' && c <= 'f' ) + else if (c >= 'a' && c <= 'f') return c - 'a' + 10; - if ( c >= 'A' && c <= 'F' ) + else if (c >= 'A' && c <= 'F') return c - 'A' + 10; - - return 0; + else + return 0; } static void send301(struct connstruct *cn) { char buf[2048]; - snprintf(buf, sizeof(buf), "HTTP/1.1 301 Moved Permanently\nLocation: %s/\n\n\n\n301 Moved Permanently\n\n

Moved Permanently

\nThe document has moved here.

\n


\n\n", cn->filereq, cn->filereq); + snprintf(buf, sizeof(buf), + "HTTP/1.1 301 Moved Permanently\nLocation: %s/\n\n" + "\n" + "\n301 Moved Permanently\n" + "\n

Moved Permanently

\n" + "The document has moved here.

\n" + "


\n\n", cn->filereq, cn->filereq); special_write(cn, buf, strlen(buf)); } static void send404(struct connstruct *cn) { char buf[1024]; - sprintf(buf, "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\n\n404 Not Found

It ain't there my friend. (404 Not Found)

\n\n"); + 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); + + /* Add directory slash if not there */ + if (isdir(cn->actualfile) && + cn->actualfile[strlen(cn->actualfile)-1] != '/') + strcat(cn->actualfile, "/"); + +#ifdef WIN32 + /* convert all the forward slashes to back slashes */ + { + char *t = cn->actualfile; + while ((t = strchr(t, '/'))) + { + *t++ = '\\'; + } + } +#endif +} + +static int sanitizefile(const char *buf) +{ + int len, i; + + // 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 . + // Notice, GOBBLES, that this includes ".." + if (buf[i] == '/' && buf[i+1] == '.') + return 0; + } + + return 1; +} + +static int sanitizehost(char *buf) +{ + while (*buf != '\0') + { + // Handle the port + if (*buf == ':') + { + *buf = '\0'; + return 1; + } + + // Enforce some basic URL rules... + if (isalnum(*buf)==0 && *buf != '-' && *buf != '.') return 0; + if (*buf == '.' && *(buf+1) == '.') return 0; + if (*buf == '.' && *(buf+1) == '-') return 0; + if (*buf == '-' && *(buf+1) == '.') return 0; + buf++; + } + + return 1; +} + diff --git a/www/index.html b/www/index.html index 86133dd77..5a391a34c 100644 --- a/www/index.html +++ b/www/index.html @@ -1,7 +1,7 @@ An Overview of Cryptography - +

@@ -12,7 +12,7 @@ An Overview of Cryptography

Gary C. Kessler
May 1998
-(26 September 2005) +(1 August 2006)


@@ -193,7 +193,7 @@ algorithms that will be discussed are (Figure 1):
- +

FIGURE 1: Three types of cryptography: secret-key, public key, and hash function.

@@ -366,7 +366,7 @@ Telegraph and Telephone (NTT) Corp. and Mitsubishi Electric Corporation and suitability for both software and hardware implementations on common 32-bit processors as well as 8-bit processors (e.g., smart cards, cryptographic hardware, and embedded systems). Also described in - RFC 3713.

+ RFC 3713. Camellia's application in IPsec is described in RFC 4312.

  • MISTY1: Developed at Mitsubishi Electric Corp., a block cipher using a 128-bit key and 64-bit blocks, and a variable number of @@ -385,7 +385,7 @@ signaling data for emerging mobile communications systems.

  • SEED: A block cipher using 128-bit blocks and 128-bit keys. Developed by the Korea Information Security Agency (KISA) and adopted as a national -standard encryption algorithm in South Korea. Also described in RFC 4009.

  • +standard encryption algorithm in South Korea. Also described in RFC 4269.

  • Skipjack: SKC scheme proposed for Capstone. Although the details of the algorithm @@ -463,11 +463,16 @@ large prime numbers. In fact, large prime numbers, like small prime numbers, only have two factors!) The ability for computers to factor large numbers, and therefore attack schemes such as RSA, is rapidly improving and systems today can find the prime factors of numbers with -more than 140 digits. The presumed protection of RSA, however, is that -users can easily increase the key size to always stay ahead of the -computer processing curve. As an aside, the patent for RSA expired in -September 2000 which does not appear to have affected RSA's popularity -one way or the other. A detailed example of RSA is presented below in Section 5.3.

  • +more than 200 digits. Nevertheless, if a large number is created from +two prime factors that are roughly the same size, there is no known +factorization algorithm that will solve the problem in a reasonable +amount of time; a 2005 test to factor a 200-digit number took 1.5 years +and over 50 years of compute time (see the Wikipedia article on integer factorization.) +Regardless, one presumed protection of RSA is that users can easily +increase the key size to always stay ahead of the computer processing +curve. As an aside, the patent for RSA expired in September 2000 which +does not appear to have affected RSA's popularity one way or the other. +A detailed example of RSA is presented below in Section 5.3.

  • Diffie-Hellman: After the RSA algorithm was published, Diffie and Hellman came up with @@ -590,17 +595,7 @@ recovered. Hash algorithms are typically used to provide a digital fingerprin of a file's contents, often used to ensure that the file has not been altered by an intruder or virus. Hash functions are also commonly employed by many operating systems to encrypt passwords. Hash -functions, then, help preserve the integrity of a file.

    -

    -Hash functions are sometimes misunderstood and some -sources claim that no two files can have the same hash value. This -isn't true, strictly speaking. Consider a hash function that provides a -128-bit hash value. There are, obviously, 2128 possible hash values. But there are a lot more than 2128 possible -files. Therefore, there have to be multiple files — in fact, there have -to be an infinite number of files! — that can have the same 128-bit -hash value. The difficulty is finding two files with the same -hash! What is, indeed, very hard to do is to try to create a file that -has a given hash value so as to force a hash value collision.

    +functions, then, provide a measure of the integrity of a file.

    Hash algorithms that are in common use today include:

    @@ -616,27 +611,60 @@ manipulation is made to the original data. MD5 has been implemented in a large number of products although several weaknesses in the algorithm were demonstrated by German cryptographer Hans Dobbertin in 1996.

  • -
  • Secure Hash Algorithm (SHA): Algorithm for NIST's Secure Hash Standard (SHS). SHA-1 produces a 160-bit hash value and was -originally published as FIPS 180-1 and RFC 3174. FIPS 180-2 +originally published as FIPS 180-1 and RFC 3174. FIPS 180-2 describes five algorithms in the SHS: SHA-1 plus SHA-224, SHA-256, SHA-384, and SHA-512 which can produce hash values that are 224, 256, -384, or 512 bits in length, respectively.

  • - +384, or 512 bits in length, respectively. SHA-224, -256, -384, and -52 +are also described in RFC 4634.

  • RIPEMD: A series of message digests that initially came from the RIPE (RACE Integrity Primitives Evaluation) project. RIPEMD-160 was designed by Hans Dobbertin, Antoon Bosselaers, and Bart Preneel, and optimized for 32-bit processors to replace the then-current 128-bit hash functions. Other versions include RIPEMD-256, RIPEMD-320, and RIPEMD-128.

  • -
  • HAVAL (HAsh of VAriable Length): Designed by Y. Zheng, J. Pieprzyk and J. Seberry, a hash algorithm with many levels of security. HAVAL can create hash values that are 128, 160, 192, 224, or 256 bits in length.

  • +
  • Whirlpool: A relatively new hash function, designed by V. Rijmen and P.S.L.M. Barreto. Whirlpool operates on messages less than 2256 +bits in length, and produces a message digest of 512 bits. The design +of this has function is very different than that of MD5 and SHA-1, +making it immune to the same attacks as on those hashes (see below).

  • +

    -For additional information, see David Hopwood's MessageDigest Algorithms page.

    +Hash functions are sometimes misunderstood and some +sources claim that no two files can have the same hash value. This is, +in fact, not correct. Consider a hash function that provides a 128-bit +hash value. There are, obviously, 2128 possible hash values. But there are a lot more than 2128 possible +files. Therefore, there have to be multiple files — in fact, there have +to be an infinite number of files! — that can have the same 128-bit +hash value.

    +

    +The difficulty is finding two files with the same +hash! What is, indeed, very hard to do is to try to create a file that +has a given hash value so as to force a hash value collision — which is +the reason that hash functions are used extensively for information +security and computer forensics applications. Alas, researchers in 2004 +found that practical collision attacks could be launched on +MD5, SHA-1, and other hash algorithms. At this time, there is no +obvious successor to MD5 and SHA-1 that could be put into use quickly; +there are so many products using these hash functions that it could +take many years to flush out all use of 128- and 160-bit hashes. +Readers interested in this problem should read the following:

    + + + +

    +An excellent review of the situation with hash collisions can be found in RFC 4270 (by P. Hoffman and B. Schneier, November 2005). And for additional information on hash functions, see David Hopwood's MessageDigest Algorithms page.

    3.4. Why Three Encryption Techniques?

    @@ -663,7 +691,7 @@ public-key cryptography.


    - +

    FIGURE 2: Sample application of the three cryptographic techniques for secure communication.

    @@ -972,7 +1000,7 @@ other secure means.

    - +

    FIGURE 3: Kerberos architecture.

    @@ -1065,7 +1093,7 @@ signature of the certificate issuer, and perhaps other information.

    - +

    FIGURE 4: GTE Cybertrust Global Root-issued certificate as viewed
    by Netscape Navigator V4.

    @@ -1238,6 +1266,11 @@ Standards and Technology (NIST) as standards for the U.S. Government. A PCMCIA card developed by NSA that implements the Capstone algorithms, intended for use with the Defense Messaging Service (DMS). +GOST +GOST is a family of algorithms that +is defined in the Russian cryptographic standards. Although most of the +specifications are written in Russian, RFC 4357 provides supplemental information and specifications so that the algorithms can be used effectively in Internet applications. + IP Security Protocol (IPsec) The IPsec protocol suite is used to @@ -1245,24 +1278,37 @@ provide privacy and authentication services at the IP layer. An overview of the protocol suite and of the documents comprising IPsec can be found in RFC 2411. Other documents include:
      -
    • RFC 2401: IP security architecture. -
    • RFC 2402: +
    • RFC 4301: IP security architecture. +
    • RFC 4302: IP Authentication Header (AH), one of the two primary IPsec functions; AH provides connectionless integrity and data origin authentication for IP datagrams and protects against replay attacks. -
    • RFC 2403: Describes use of the HMAC with MD5 algorithm for data origin authentication and integrity protection in both AH and ESP. -
    • RFC 2404: Describes use of the HMAC with SHA-1 algorithm for data origin authentication and integrity protection in both AH and ESP. -
    • RFC 2405: Describes use of DES-CBC (DES in Cipher Block Chaining Mode) for confidentiality in ESP. -
    • RFC 2406: +
    • RFC 4303: IP Encapsulating Security Payload (ESP), the other primary IPsec function; ESP provides a variety of security services within IPsec. -
    • RFC 2407: Describes the application of ISAKMP to IPsec. -
    • RFC 2408: Describes ISAKMP, a framework for key management and security associations. -
    • RFC 2409: -The Internet Key Exchange (IKE) algorithm, using part of Oakley and -part of SKEME in conjunction with ISAKMP to obtain authenticated keying -material for use with ISAKMP, and for other security associations such -as AH and ESP. +
    • RFC 4304: +Extended Sequence Number (ESN) Addendum, allows for negotiation of a +32- or 64- bit sequence number, used to detect replay attacks.
    • +
    • RFC 4305: Cryptographic algorithm implementation requirements for ESP and AH.
    • +
    • RFC 4306: +The Internet Key Exchange (IKE) protocol, version 2, providing for +mutual authentication and establishing and maintaining security +associations.
    • +
        +
      • IKE v1 was described in three separate documents, RFC 2407 (application of ISAKMP to IPsec), RFC 2408 (ISAKMP, a framework for key management and security associations), and RFC 2409 +(IKE, using part of Oakley and part of SKEME in conjunction with ISAKMP +to obtain authenticated keying material for use with ISAKMP, and for +other security associations such as AH and ESP). IKE v1 is obsoleted +with the introdcution of IKEv2.
      • +
      +
    • RFC 4307: Cryptographic algoritms used with IKEv2.
    • +
    • RFC 4308: Crypto suites for IPsec, IKE, and IKEv2.
    • +
    • RFC 4309: The use of AES in CBC-MAC mode with IPsec ESP.
    • +
    • RFC 4312: The use of the Camellia cipher algorithm in IPsec.
    • +
    • RFC 4359: The Use of RSA/SHA-1 Signatures within Encapsulating Security Payload (ESP) and Authentication Header (AH).
    • +
    • RFC 4434: Describes AES-XCBC-PRF-128, a pseudo-random function derived from the AES for use with IKE.
    • +
    • RFC 2403: Describes use of the HMAC with MD5 algorithm for data origin authentication and integrity protection in both AH and ESP. +
    • RFC 2405: Describes use of DES-CBC (DES in Cipher Block Chaining Mode) for confidentiality in ESP.
    • RFC 2410: Defines use of the NULL encryption algorithm (i.e., provides authentication and integrity without confidentiality) in ESP.
    • RFC 2412: Describes OAKLEY, a key determination and distribution protocol.
    • RFC 2451: Describes use of Cipher Block Chaining (CBC) mode cipher algorithms with ESP. @@ -1374,7 +1420,19 @@ Windows NT Server running Internet Information Server (IIS) 4.0 with a valid SGC certificate. SGC is available in 32-bit Windows versions of Internet Explorer (IE) 4.0, and support for Mac, Unix, and 16-bit Windows versions of IE is expected in the future. -Simple Key-Management for Internet Protocol (SKIP) +Simple Authentication and Security Layer (SASL) +(SASL) is a framework for providing +authentication and data security services in connection-oriented +protocols (a la TCP). It provides a structured interface and allows new +protocols to reuse existing authentication mechanisms and allows old +protocols to make use of new mechanisms. +

      It has been common practice on the Internet to permit anonymous +access to various services, employing a plain-text password using a +user name of "anonymous" and a password of an email address or some +other identifying information. New IETF protocols disallow plain-text +logins. The Anonymous SASL Mechanism (RFC 4505) provides a method for anonymous logins within the SASL framework. + +

      Simple Key-Management for Internet Protocol (SKIP) Key management scheme for secure IP communication, specifically for IPsec, and designed by Aziz and Diffie. SKIP essentially defines a public key infrastructure for the Internet @@ -1739,10 +1797,13 @@ Cipher Block Chaining (CBC), Cipher Feedback (CFB), and Output Feedback (OFB). Despite all of these options, ECB is the most commonly deployed mode of operation.

      -Although other block ciphers will replace DES, it is -still interesting to see how DES encryption is performed. Not only is -it sort of interesting, but DES remains in many products and we will -continue to see DES for some years to come.

      +NIST finally declared DES obsolete in 2004, and withdrew FIPS 46-3, 74, and 81 (Federal Register, July 26, 2004, 69(142), 44509-44510). +Although other block ciphers will replace DES, it is still interesting +to see how DES encryption is performed; not only is it sort of neat, +but DES was the first crypto scheme commonly seen in non-govermental +applications and was the catalyst for modern "public" cryptography. DES +remains in many products — and cryptography students and cryptographers +will continue to study DES for years to come.

      DES Operational Overview

      @@ -1756,7 +1817,7 @@ of randomness, or entropy).


      - +

      FIGURE 6: DES enciphering algorithm.

      @@ -2148,7 +2209,7 @@ nonrepudiation for the classic Internet Protocol (IP). Although intended primarily for IP version 6 (IPv6), IPsec can also be employed by the current version of IP, namely IP version 4 (IPv4).

      -As shown in Table 3, IPsec is described in nearly a dozen RFCs. RFC 2401, in particular, describes the overall IP security architecture and RFC 2411 provides an overview of the IPsec protocol suite and the documents describing it.

      +As shown in Table 3, IPsec is described in nearly a dozen RFCs. RFC 4301, in particular, describes the overall IP security architecture and RFC 2411 provides an overview of the IPsec protocol suite and the documents describing it.

      IPsec can provide either message authentication and/or encryption. The latter requires more processing than the former, but @@ -2173,7 +2234,7 @@ endpoints requires the establishment of two SAs (one in each direction).<

    • security protocol (AH or ESP) identifier

    -The IP Authentication Header (AH), described in RFC 2402, provides a mechanism for data integrity and data origin authentication for IP packets using HMAC with MD5 (RFC 2403), HMAC with SHA-1 (RFC 2404), or HMAC with RIPEMD (RFC 2857).

    +The IP Authentication Header (AH), described in RFC 4302, provides a mechanism for data integrity and data origin authentication for IP packets using HMAC with MD5 (RFC 2403), HMAC with SHA-1 (RFC 2404), or HMAC with RIPEMD (RFC 2857). See also RFC 4305.


    @@ -2190,12 +2251,12 @@ endpoints requires the establishment of two SAs (one in each direction).< | Sequence Number Field | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | - + Authentication Data (variable) | + + Integrity Check Value-ICV (variable) | | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    -

    FIGURE 10: IPsec Authentication Header format. (From RFC 2402)

    +

    FIGURE 10: IPsec Authentication Header format. (From RFC 4302)



    @@ -2242,38 +2303,44 @@ algorithm specified by the SA, such as DES, MD5, or SHA-1. Other algorithms may also be supported.

    -The IP Encapsulating Security Payload (ESP), described in RFC 2406, +The IP Encapsulating Security Payload (ESP), described in RFC 4303, provides message integrity and privacy mechanisms in addition to authentication. As in AH, ESP uses HMAC with MD5, SHA-1, or RIPEMD -authentication (RFC 2403/RFC 2404/RFC 2857); privacy is provided using DES-CBC encryption (RFC 2405), NULL encryption (RFC 2410), other CBC-mode algorithms (RFC 2451), or AES (RFC 3686).

    +authentication (RFC 2403/RFC 2404/RFC 2857); privacy is provided using DES-CBC encryption (RFC 2405), NULL encryption (RFC 2410), other CBC-mode algorithms (RFC 2451), or AES (RFC 3686). See also RFC 4305 and RFC 4308.


    -
    +
         0                   1                   2                   3
         0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    -   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    -   |               Security Parameters Index (SPI)                 |
    -   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    -   |                      Sequence Number                          |
    -   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    -   |                    Payload Data (variable)                    |
    -   ~                                                               ~
    -   |                                                               |
    -   +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    -   |               |     Padding (0-255 bytes)                     |
    -   +-+-+-+-+-+-+-+-+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    -   |                               |  Pad Length   | Next Header   |
    -   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    -   |                 Authentication Data (variable)                |
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ----
    +   |               Security Parameters Index (SPI)                 | ^Int.
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Cov-
    +   |                      Sequence Number                          | |ered
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ----  
    +   |                    Payload Data* (variable)                   | |   ^
    +   ~                                                               ~ |   |
    +   |                                                               | |Conf.
    +   +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |Cov-
    +   |               |     Padding (0-255 bytes)                     | |ered*
    +   +-+-+-+-+-+-+-+-+               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |   |
    +   |                               |  Pad Length   | Next Header   | v   v
    +   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ------
    +   |         Integrity Check Value-ICV   (variable)                |
        ~                                                               ~
        |                                                               |
        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    +
    +       * If included in the Payload field, cryptographic synchronization
    +         data, e.g., an Initialization Vector (IV), usually is not
    +         encrypted per se, although it often is referred to as being
    +         being part of the ciphertext.
    +
     

    -

    FIGURE 11: IPsec Encapsulating Security Payload format. (From RFC 2406)

    +

    FIGURE 11: IPsec Encapsulating Security Payload format. (From RFC 4303)



    @@ -2322,60 +2389,62 @@ This mode of operation is supported by both hosts and security gateways.
    <
    -
    +
    -    ORIGINAL PACKET BEFORE APPLYING AH
    +  ORIGINAL PACKET BEFORE APPLYING AH
     
    -            ----------------------------
    -      IPv4  |orig IP hdr  |     |      |
    -            |(any options)| TCP | Data |
    -            ----------------------------
    +         ----------------------------
    +   IPv4  |orig IP hdr  |     |      |
    +         |(any options)| TCP | Data |
    +         ----------------------------
     
    -            ---------------------------------------
    -      IPv6  |             | ext hdrs |     |      |
    -            | orig IP hdr |if present| TCP | Data |
    -            ---------------------------------------
    +         ---------------------------------------
    +   IPv6  |             | ext hdrs |     |      |
    +         | orig IP hdr |if present| TCP | Data |
    +         ---------------------------------------
    +
    +  AFTER APPLYING AH (TRANSPORT MODE)
    +
    +          -------------------------------------------------------
    +    IPv4  |original IP hdr (any options) | AH | TCP |    Data   |
    +          -------------------------------------------------------
    +          |<- mutable field processing ->|<- immutable fields ->|
    +          |<----- authenticated except for mutable fields ----->|
    +
    +         ------------------------------------------------------------
    +   IPv6  |             |hop-by-hop, dest*, |    | dest |     |      |
    +         |orig IP hdr  |routing, fragment. | AH | opt* | TCP | Data |
    +         ------------------------------------------------------------
    +         |<--- mutable field processing -->|<-- immutable fields -->|
    +         |<---- authenticated except for mutable fields ----------->|
    +
    +               * = if present, could be before AH, after AH, or both
     
     
    -    AFTER APPLYING AH (TRANSPORT MODE)
    +  AFTER APPLYING AH (TUNNEL MODE)
     
    -            ---------------------------------
    -      IPv4  |orig IP hdr  |    |     |      |
    -            |(any options)| AH | TCP | Data |
    -            ---------------------------------
    -            |<------- authenticated ------->|
    -                 except for mutable fields
    +        ----------------------------------------------------------------
    +   IPv4 |                              |    | orig IP hdr*  |   |      |
    +        |new IP header * (any options) | AH | (any options) |TCP| Data |
    +        ----------------------------------------------------------------
    +        |<- mutable field processing ->|<------ immutable fields ----->|
    +        |<- authenticated except for mutable fields in the new IP hdr->|
     
    -            ------------------------------------------------------------
    -      IPv6  |             |hop-by-hop, dest*, |    | dest |     |      |
    -            |orig IP hdr  |routing, fragment. | AH | opt* | TCP | Data |
    -            ------------------------------------------------------------
    -            |<---- authenticated except for mutable fields ----------->|
    +        --------------------------------------------------------------
    +   IPv6 |           | ext hdrs*|    |            | ext hdrs*|   |    |
    +        |new IP hdr*|if present| AH |orig IP hdr*|if present|TCP|Data|
    +        --------------------------------------------------------------
    +        |<--- mutable field -->|<--------- immutable fields -------->|
    +        |       processing     |
    +        |<-- authenticated except for mutable fields in new IP hdr ->|
     
    -                 * = if present, could be before AH, after AH, or both
    +          * = if present, construction of outer IP hdr/extensions and
    +              modification of inner IP hdr/extensions is discussed in
    +              the Security Architecture document.
     
    -
    -    AFTER APPLYING AH (TUNNEL MODE)
    -
    -          ------------------------------------------------
    -    IPv4  | new IP hdr* |    | orig IP hdr*  |    |      |
    -          |(any options)| AH | (any options) |TCP | Data |
    -          ------------------------------------------------
    -          |<- authenticated except for mutable fields -->|
    -
    -          |           in the new IP hdr                  |
    -
    -          --------------------------------------------------------------
    -    IPv6  |           | ext hdrs*|    |            | ext hdrs*|   |    |
    -          |new IP hdr*|if present| AH |orig IP hdr*|if present|TCP|Data|
    -          --------------------------------------------------------------
    -          |<-- authenticated except for mutable fields in new IP hdr ->|
    -
    -           * = construction of outer IP hdr/extensions and modification
    -               of inner IP hdr/extensions is discussed below.
     

    -

    FIGURE 12: IPsec tunnel and transport modes for AH. (Adapted from RFC 2402)

    +

    FIGURE 12: IPsec tunnel and transport modes for AH. (Adapted from RFC 4302)



    @@ -2397,7 +2466,7 @@ Note, in particular, that the address fields are not mutable.


    -
    +
         ORIGINAL PACKET BEFORE APPLYING ESP
     
    @@ -2416,17 +2485,17 @@ Note, in particular, that the address fields are not mutable.

    ------------------------------------------------- IPv4 |orig IP hdr | ESP | | | ESP | ESP| - |(any options)| Hdr | TCP | Data | Trailer |Auth| + |(any options)| Hdr | TCP | Data | Trailer | ICV| ------------------------------------------------- - |<----- encrypted ---->| - |<------ authenticated ----->| + |<---- encryption ---->| + |<-------- integrity ------->| --------------------------------------------------------- - IPv6 | orig |hop-by-hop,dest*,|ESP|dest| | | ESP | ESP| - |IP hdr|routing,fragment.|hdr|opt*|TCP|Data|Trailer|Auth| + IPv6 | orig |hop-by-hop,dest*,| |dest| | | ESP | ESP| + |IP hdr|routing,fragment.|ESP|opt*|TCP|Data|Trailer| ICV| --------------------------------------------------------- - |<---- encrypted ---->| - |<---- authenticated ---->| + |<--- encryption ---->| + |<------ integrity ------>| * = if present, could be before ESP, after ESP, or both @@ -2434,24 +2503,27 @@ Note, in particular, that the address fields are not mutable.

    AFTER APPLYING ESP (TUNNEL MODE) ----------------------------------------------------------- - IPv4 | new IP hdr | ESP | orig IP hdr | | | ESP | ESP| - |(any options)| hdr | (any options) |TCP|Data|Trailer|Auth| + IPv4 | new IP hdr+ | | orig IP hdr+ | | | ESP | ESP| + |(any options)| ESP | (any options) |TCP|Data|Trailer| ICV| ----------------------------------------------------------- - |<--------- encrypted ---------->| - |<----------- authenticated ---------->| + |<--------- encryption --------->| + |<------------- integrity ------------>| ------------------------------------------------------------ - IPv6 | new+ |new ext |ESP| orig+|orig ext | | | ESP | ESP| - |IP hdr| hdrs+ |hdr|IP hdr| hdrs+ |TCP|Data|Trailer|Auth| + IPv6 | new+ |new ext | | orig+|orig ext | | | ESP | ESP| + |IP hdr| hdrs+ |ESP|IP hdr| hdrs+ |TCP|Data|Trailer| ICV| ------------------------------------------------------------ - |<--------- encrypted ----------->| - |<---------- authenticated ---------->| + |<--------- encryption ---------->| + |<------------ integrity ------------>| + + + = if present, construction of outer IP hdr/extensions and + modification of inner IP hdr/extensions is discussed in + the Security Architecture document. - + = if present

    -

    FIGURE 13: IPsec tunnel and transport modes for ESP. (Adapted from RFC 2406)

    +

    FIGURE 13: IPsec tunnel and transport modes for ESP. (Adapted from RFC 4303)



    @@ -2563,7 +2635,7 @@ found; both are supported by most common browsers (Figure 14).


    - +

    FIGURE 14: SSL v3 configuration screen (Netscape Navigator).

    @@ -2573,10 +2645,9 @@ found; both are supported by most common browsers (Figure 14).

    In 1997, SSL v3 was found to be breakable. By this time, the Internet Engineering Task Force (IETF) had already started work on a new, non-proprietary protocol called Transport Layer Security (TLS), -described in RFC 2246. -TLS extends SSL and supports additional crypto schemes, such as -Diffie-Hellman key exchange and DSS digital signatures. TLS is backward -compatible with SSL (and, in fact, is recognized as SSL v3.1).

    +described in RFC 2246. TLS extends SSL and supports additional crypto schemes, such as Diffie-Hellman key exchange and DSS digital signatures; RFC 4279 +describes the pre-shared key crypto schemes supported by TLS. TLS is +backward compatible with SSL (and, in fact, is recognized as SSL v3.1).


    @@ -2773,7 +2844,7 @@ changes the shape of the curve, and small changes in these parameters can result in major changes in the set of (x,y) solutions.


    - +

    FIGURE 16: Elliptic curve addition.

    @@ -3545,6 +3616,7 @@ New York: Macmillan, 1983.
  • Stallings, W. Cryptography and Network Security: Principles and Practice, 4th ed. Englewood Cliffs (NJ): Prentice Hall, 2006.
  • _____, (ed.) Practical Cryptography for Data Internetworks. Los Alamitos (CA): IEEE Computer Society Press, 1996.
  • Trappe, W. & Washington, L.C. Introduction to Cryptography with Codin Theory, 2nd ed. Upper Saddle River (NJ): Pearson Prentice Hall, 2006. +
  • Young, A. & Yung, M. Malicious Cryptography: Exposing Cryptovirology. New York: John Wiley & Sons, 2004.

  • On the Web: