commit c93767a200a66a2911bb10ecf4a1573eeeee30d2 Author: overweight <5324761+overweight@user.noreply.gitee.com> Date: Mon Sep 30 10:58:15 2019 -0400 Package init diff --git a/libssh-0.8.3-fix-covscan-errors.patch b/libssh-0.8.3-fix-covscan-errors.patch new file mode 100644 index 0000000..6110c82 --- /dev/null +++ b/libssh-0.8.3-fix-covscan-errors.patch @@ -0,0 +1,2065 @@ +diff --git a/examples/libssh_scp.c b/examples/libssh_scp.c +index 46199f47..ff38b830 100644 +--- a/examples/libssh_scp.c ++++ b/examples/libssh_scp.c +@@ -25,148 +25,230 @@ program. + static char **sources; + static int nsources; + static char *destination; +-static int verbosity=0; ++static int verbosity = 0; + + struct location { +- int is_ssh; +- char *user; +- char *host; +- char *path; +- ssh_session session; +- ssh_scp scp; +- FILE *file; ++ int is_ssh; ++ char *user; ++ char *host; ++ char *path; ++ ssh_session session; ++ ssh_scp scp; ++ FILE *file; + }; + + enum { +- READ, +- WRITE ++ READ, ++ WRITE + }; + +-static void usage(const char *argv0){ +- fprintf(stderr,"Usage : %s [options] [[user@]host1:]file1 ... \n" +- " [[user@]host2:]destination\n" +- "sample scp client - libssh-%s\n", +-// "Options :\n", +-// " -r : use RSA to verify host public key\n", +- argv0, +- ssh_version(0)); +- exit(0); ++static void usage(const char *argv0) { ++ fprintf(stderr, "Usage : %s [options] [[user@]host1:]file1 ... \n" ++ " [[user@]host2:]destination\n" ++ "sample scp client - libssh-%s\n", ++ // "Options :\n", ++ // " -r : use RSA to verify host public key\n", ++ argv0, ++ ssh_version(0)); ++ exit(0); + } + +-static int opts(int argc, char **argv){ +- int i; +- while((i=getopt(argc,argv,"v"))!=-1){ +- switch(i){ +- case 'v': +- verbosity++; +- break; +- default: +- fprintf(stderr,"unknown option %c\n",optopt); ++static int opts(int argc, char **argv) { ++ int i; ++ ++ while((i = getopt(argc, argv, "v")) != -1) { ++ switch(i) { ++ case 'v': ++ verbosity++; ++ break; ++ default: ++ fprintf(stderr, "unknown option %c\n", optopt); ++ usage(argv[0]); ++ return -1; ++ } ++ } ++ ++ nsources = argc - optind - 1; ++ if (nsources < 1) { + usage(argv[0]); + return -1; + } +- } +- nsources=argc-optind-1; +- if(nsources < 1){ +- usage(argv[0]); +- return -1; +- } +- sources=malloc((nsources + 1) * sizeof(char *)); +- if(sources == NULL) +- return -1; +- for(i=0;ihost=location->user=NULL; +- ptr=strchr(loc,':'); +- if(ptr != NULL){ +- location->is_ssh=1; +- location->path=strdup(ptr+1); +- *ptr='\0'; +- ptr=strchr(loc,'@'); +- if(ptr != NULL){ +- location->host=strdup(ptr+1); +- *ptr='\0'; +- location->user=strdup(loc); +- } else { +- location->host=strdup(loc); ++ sources = malloc((nsources + 1) * sizeof(char *)); ++ if (sources == NULL) { ++ return -1; + } +- } else { +- location->is_ssh=0; +- location->path=strdup(loc); +- } +- return location; +-} + +-static int open_location(struct location *loc, int flag){ +- if(loc->is_ssh && flag==WRITE){ +- loc->session=connect_ssh(loc->host,loc->user,verbosity); +- if(!loc->session){ +- fprintf(stderr,"Couldn't connect to %s\n",loc->host); +- return -1; ++ for(i = 0; i < nsources; ++i) { ++ sources[i] = argv[optind]; ++ optind++; + } +- loc->scp=ssh_scp_new(loc->session,SSH_SCP_WRITE,loc->path); +- if(!loc->scp){ +- fprintf(stderr,"error : %s\n",ssh_get_error(loc->session)); +- return -1; ++ ++ sources[i] = NULL; ++ destination = argv[optind]; ++ return 0; ++} ++ ++static void location_free(struct location *loc) ++{ ++ if (loc) { ++ if (loc->path) { ++ free(loc->path); ++ } ++ loc->path = NULL; ++ if (loc->is_ssh) { ++ if (loc->host) { ++ free(loc->host); ++ } ++ loc->host = NULL; ++ if (loc->user) { ++ free(loc->user); ++ } ++ loc->user = NULL; ++ if (loc->host) { ++ free(loc->host); ++ } ++ loc->host = NULL; ++ } ++ free(loc); + } +- if(ssh_scp_init(loc->scp)==SSH_ERROR){ +- fprintf(stderr,"error : %s\n",ssh_get_error(loc->session)); +- ssh_scp_free(loc->scp); +- loc->scp = NULL; +- return -1; ++} ++ ++static struct location *parse_location(char *loc) { ++ struct location *location; ++ char *ptr; ++ ++ location = malloc(sizeof(struct location)); ++ if (location == NULL) { ++ return NULL; + } +- return 0; +- } else if(loc->is_ssh && flag==READ){ +- loc->session=connect_ssh(loc->host, loc->user,verbosity); +- if(!loc->session){ +- fprintf(stderr,"Couldn't connect to %s\n",loc->host); +- return -1; ++ memset(location, 0, sizeof(struct location)); ++ ++ location->host = location->user = NULL; ++ ptr = strchr(loc, ':'); ++ ++ if (ptr != NULL) { ++ location->is_ssh = 1; ++ location->path = strdup(ptr+1); ++ *ptr = '\0'; ++ ptr = strchr(loc, '@'); ++ ++ if (ptr != NULL) { ++ location->host = strdup(ptr+1); ++ *ptr = '\0'; ++ location->user = strdup(loc); ++ } else { ++ location->host = strdup(loc); ++ } ++ } else { ++ location->is_ssh = 0; ++ location->path = strdup(loc); + } +- loc->scp=ssh_scp_new(loc->session,SSH_SCP_READ,loc->path); +- if(!loc->scp){ +- fprintf(stderr,"error : %s\n",ssh_get_error(loc->session)); +- return -1; ++ return location; ++} ++ ++static void close_location(struct location *loc) { ++ int rc; ++ ++ if (loc) { ++ if (loc->is_ssh) { ++ if (loc->scp) { ++ rc = ssh_scp_close(loc->scp); ++ if (rc == SSH_ERROR) { ++ fprintf(stderr, ++ "Error closing scp: %s\n", ++ ssh_get_error(loc->session)); ++ } ++ ssh_scp_free(loc->scp); ++ loc->scp = NULL; ++ } ++ if (loc->session) { ++ ssh_disconnect(loc->session); ++ ssh_free(loc->session); ++ loc->session = NULL; ++ } ++ } else { ++ if (loc->file) { ++ fclose(loc->file); ++ loc->file = NULL; ++ } ++ } + } +- if(ssh_scp_init(loc->scp)==SSH_ERROR){ +- fprintf(stderr,"error : %s\n",ssh_get_error(loc->session)); +- ssh_scp_free(loc->scp); +- loc->scp = NULL; +- return -1; ++} ++ ++static int open_location(struct location *loc, int flag) { ++ if (loc->is_ssh && flag == WRITE) { ++ loc->session = connect_ssh(loc->host, loc->user, verbosity); ++ if (!loc->session) { ++ fprintf(stderr, "Couldn't connect to %s\n", loc->host); ++ return -1; ++ } ++ ++ loc->scp = ssh_scp_new(loc->session, SSH_SCP_WRITE, loc->path); ++ if (!loc->scp) { ++ fprintf(stderr, "error : %s\n", ssh_get_error(loc->session)); ++ ssh_disconnect(loc->session); ++ ssh_free(loc->session); ++ loc->session = NULL; ++ return -1; ++ } ++ ++ if (ssh_scp_init(loc->scp) == SSH_ERROR) { ++ fprintf(stderr, "error : %s\n", ssh_get_error(loc->session)); ++ ssh_scp_free(loc->scp); ++ loc->scp = NULL; ++ ssh_disconnect(loc->session); ++ ssh_free(loc->session); ++ loc->session = NULL; ++ return -1; ++ } ++ return 0; ++ } else if (loc->is_ssh && flag == READ) { ++ loc->session = connect_ssh(loc->host, loc->user, verbosity); ++ if (!loc->session) { ++ fprintf(stderr, "Couldn't connect to %s\n", loc->host); ++ return -1; ++ } ++ ++ loc->scp = ssh_scp_new(loc->session, SSH_SCP_READ, loc->path); ++ if (!loc->scp) { ++ fprintf(stderr, "error : %s\n", ssh_get_error(loc->session)); ++ ssh_disconnect(loc->session); ++ ssh_free(loc->session); ++ loc->session = NULL; ++ return -1; ++ } ++ ++ if (ssh_scp_init(loc->scp) == SSH_ERROR) { ++ fprintf(stderr, "error : %s\n", ssh_get_error(loc->session)); ++ ssh_scp_free(loc->scp); ++ loc->scp = NULL; ++ ssh_disconnect(loc->session); ++ ssh_free(loc->session); ++ loc->session = NULL; ++ return -1; ++ } ++ return 0; ++ } else { ++ loc->file = fopen(loc->path, flag == READ ? "r":"w"); ++ if (!loc->file) { ++ if (errno == EISDIR) { ++ if (chdir(loc->path)) { ++ fprintf(stderr, ++ "Error changing directory to %s: %s\n", ++ loc->path, strerror(errno)); ++ return -1; ++ } ++ return 0; ++ } ++ fprintf(stderr, ++ "Error opening %s: %s\n", ++ loc->path, strerror(errno)); ++ return -1; ++ } ++ return 0; + } +- return 0; +- } else { +- loc->file=fopen(loc->path,flag==READ ? "r":"w"); +- if(!loc->file){ +- if(errno==EISDIR){ +- if(chdir(loc->path)){ +- fprintf(stderr,"Error changing directory to %s: %s\n",loc->path,strerror(errno)); +- return -1; +- } +- return 0; +- } +- fprintf(stderr,"Error opening %s: %s\n",loc->path,strerror(errno)); +- return -1; +- } +- return 0; +- } +- return -1; ++ return -1; + } + + /** @brief copies files from source location to destination +@@ -174,155 +256,197 @@ static int open_location(struct location *loc, int flag){ + * @param dest destination location + * @param recursive Copy also directories + */ +-static int do_copy(struct location *src, struct location *dest, int recursive){ +- int size; +- socket_t fd; +- struct stat s; +- int w,r; +- char buffer[16384]; +- int total=0; +- int mode; +- char *filename = NULL; +- /* recursive mode doesn't work yet */ +- (void)recursive; +- /* Get the file name and size*/ +- if(!src->is_ssh){ +- fd = fileno(src->file); +- if (fd < 0) { +- fprintf(stderr, "Invalid file pointer, error: %s\n", strerror(errno)); +- return -1; ++static int do_copy(struct location *src, struct location *dest, int recursive) { ++ int size; ++ socket_t fd; ++ struct stat s; ++ int w, r; ++ char buffer[16384]; ++ int total = 0; ++ int mode; ++ char *filename = NULL; ++ /* recursive mode doesn't work yet */ ++ (void)recursive; ++ /* Get the file name and size*/ ++ if (!src->is_ssh) { ++ fd = fileno(src->file); ++ if (fd < 0) { ++ fprintf(stderr, ++ "Invalid file pointer, error: %s\n", ++ strerror(errno)); ++ return -1; ++ } ++ r = fstat(fd, &s); ++ if (r < 0) { ++ return -1; ++ } ++ size = s.st_size; ++ mode = s.st_mode & ~S_IFMT; ++ filename = ssh_basename(src->path); ++ } else { ++ size = 0; ++ do { ++ r = ssh_scp_pull_request(src->scp); ++ if (r == SSH_SCP_REQUEST_NEWDIR) { ++ ssh_scp_deny_request(src->scp, "Not in recursive mode"); ++ continue; ++ } ++ if (r == SSH_SCP_REQUEST_NEWFILE) { ++ size = ssh_scp_request_get_size(src->scp); ++ filename = strdup(ssh_scp_request_get_filename(src->scp)); ++ mode = ssh_scp_request_get_permissions(src->scp); ++ //ssh_scp_accept_request(src->scp); ++ break; ++ } ++ if (r == SSH_ERROR) { ++ fprintf(stderr, ++ "Error: %s\n", ++ ssh_get_error(src->session)); ++ ssh_string_free_char(filename); ++ return -1; ++ } ++ } while(r != SSH_SCP_REQUEST_NEWFILE); + } +- r = fstat(fd, &s); +- if (r < 0) { +- return -1; ++ ++ if (dest->is_ssh) { ++ r = ssh_scp_push_file(dest->scp, src->path, size, mode); ++ // snprintf(buffer, sizeof(buffer), "C0644 %d %s\n", size, src->path); ++ if (r == SSH_ERROR) { ++ fprintf(stderr, ++ "error: %s\n", ++ ssh_get_error(dest->session)); ++ ssh_string_free_char(filename); ++ ssh_scp_free(dest->scp); ++ dest->scp = NULL; ++ return -1; ++ } ++ } else { ++ if (!dest->file) { ++ dest->file = fopen(filename, "w"); ++ if (!dest->file) { ++ fprintf(stderr, ++ "Cannot open %s for writing: %s\n", ++ filename, strerror(errno)); ++ if (src->is_ssh) { ++ ssh_scp_deny_request(src->scp, "Cannot open local file"); ++ } ++ ssh_string_free_char(filename); ++ return -1; ++ } ++ } ++ if (src->is_ssh) { ++ ssh_scp_accept_request(src->scp); ++ } + } +- size=s.st_size; +- mode = s.st_mode & ~S_IFMT; +- filename=ssh_basename(src->path); +- } else { +- size=0; ++ + do { +- r=ssh_scp_pull_request(src->scp); +- if(r==SSH_SCP_REQUEST_NEWDIR){ +- ssh_scp_deny_request(src->scp,"Not in recursive mode"); +- continue; +- } +- if(r==SSH_SCP_REQUEST_NEWFILE){ +- size=ssh_scp_request_get_size(src->scp); +- filename=strdup(ssh_scp_request_get_filename(src->scp)); +- mode=ssh_scp_request_get_permissions(src->scp); +- //ssh_scp_accept_request(src->scp); +- break; +- } +- if(r==SSH_ERROR){ +- fprintf(stderr,"Error: %s\n",ssh_get_error(src->session)); ++ if (src->is_ssh) { ++ r = ssh_scp_read(src->scp, buffer, sizeof(buffer)); ++ if (r == SSH_ERROR) { ++ fprintf(stderr, ++ "Error reading scp: %s\n", ++ ssh_get_error(src->session)); ++ ssh_string_free_char(filename); ++ return -1; ++ } ++ ++ if (r == 0) { ++ break; ++ } ++ } else { ++ r = fread(buffer, 1, sizeof(buffer), src->file); ++ if (r == 0) { ++ break; ++ } ++ ++ if (r < 0) { ++ fprintf(stderr, ++ "Error reading file: %s\n", ++ strerror(errno)); ++ ssh_string_free_char(filename); ++ return -1; ++ } ++ } ++ ++ if (dest->is_ssh) { ++ w = ssh_scp_write(dest->scp, buffer, r); ++ if (w == SSH_ERROR) { ++ fprintf(stderr, ++ "Error writing in scp: %s\n", ++ ssh_get_error(dest->session)); ++ ssh_scp_free(dest->scp); ++ dest->scp = NULL; ++ ssh_string_free_char(filename); ++ return -1; ++ } ++ } else { ++ w = fwrite(buffer, r, 1, dest->file); ++ if (w <= 0) { ++ fprintf(stderr, ++ "Error writing in local file: %s\n", ++ strerror(errno)); + ssh_string_free_char(filename); +- return -1; +- } +- } while(r != SSH_SCP_REQUEST_NEWFILE); +- } +- +- if(dest->is_ssh){ +- r=ssh_scp_push_file(dest->scp,src->path, size, mode); +- // snprintf(buffer,sizeof(buffer),"C0644 %d %s\n",size,src->path); +- if(r==SSH_ERROR){ +- fprintf(stderr,"error: %s\n",ssh_get_error(dest->session)); +- ssh_string_free_char(filename); +- ssh_scp_free(dest->scp); +- dest->scp = NULL; +- return -1; +- } +- } else { +- if(!dest->file){ +- dest->file=fopen(filename,"w"); +- if(!dest->file){ +- fprintf(stderr,"Cannot open %s for writing: %s\n",filename,strerror(errno)); +- if(src->is_ssh) +- ssh_scp_deny_request(src->scp,"Cannot open local file"); +- ssh_string_free_char(filename); +- return -1; +- } +- } +- if(src->is_ssh){ +- ssh_scp_accept_request(src->scp); +- } +- } +- do { +- if(src->is_ssh){ +- r=ssh_scp_read(src->scp,buffer,sizeof(buffer)); +- if(r==SSH_ERROR){ +- fprintf(stderr,"Error reading scp: %s\n",ssh_get_error(src->session)); +- ssh_string_free_char(filename); +- return -1; +- } +- if(r==0) +- break; +- } else { +- r=fread(buffer,1,sizeof(buffer),src->file); +- if(r==0) +- break; +- if(r<0){ +- fprintf(stderr,"Error reading file: %s\n",strerror(errno)); +- ssh_string_free_char(filename); +- return -1; +- } +- } +- if(dest->is_ssh){ +- w=ssh_scp_write(dest->scp,buffer,r); +- if(w == SSH_ERROR){ +- fprintf(stderr,"Error writing in scp: %s\n",ssh_get_error(dest->session)); +- ssh_scp_free(dest->scp); +- dest->scp=NULL; +- ssh_string_free_char(filename); +- return -1; +- } +- } else { +- w=fwrite(buffer,r,1,dest->file); +- if(w<=0){ +- fprintf(stderr,"Error writing in local file: %s\n",strerror(errno)); +- ssh_string_free_char(filename); +- return -1; +- } +- } +- total+=r; +- +- } while(total < size); +- ssh_string_free_char(filename); +- printf("wrote %d bytes\n",total); +- return 0; ++ return -1; ++ } ++ } ++ total += r; ++ ++ } while(total < size); ++ ++ ssh_string_free_char(filename); ++ printf("wrote %d bytes\n", total); ++ return 0; + } + +-int main(int argc, char **argv){ +- struct location *dest, *src; +- int i; +- int r; +- if(opts(argc,argv)<0) +- return EXIT_FAILURE; +- dest=parse_location(destination); +- if(open_location(dest,WRITE)<0) +- return EXIT_FAILURE; +- for(i=0;iis_ssh && dest->scp != NULL) { +- r=ssh_scp_close(dest->scp); +- if(r == SSH_ERROR){ +- fprintf(stderr,"Error closing scp: %s\n",ssh_get_error(dest->session)); +- ssh_scp_free(dest->scp); +- dest->scp=NULL; +- return -1; +- } +- } else { +- fclose(dest->file); +- dest->file=NULL; +- } +- ssh_disconnect(dest->session); +- ssh_finalize(); +- return 0; ++ ++ for (i = 0; i < nsources; ++i) { ++ src = parse_location(sources[i]); ++ if (src == NULL) { ++ r = EXIT_FAILURE; ++ goto close_dest; ++ } ++ ++ if (open_location(src, READ) < 0) { ++ location_free(src); ++ r = EXIT_FAILURE; ++ goto close_dest; ++ } ++ ++ if (do_copy(src, dest, 0) < 0) { ++ close_location(src); ++ location_free(src); ++ break; ++ } ++ ++ close_location(src); ++ location_free(src); ++ } ++ ++ r = 0; ++ ++close_dest: ++ close_location(dest); ++ location_free(dest); ++end: ++ return r; + } +diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h +index a83bd8a2..a5d046f0 100644 +--- a/include/libssh/libssh.h ++++ b/include/libssh/libssh.h +@@ -630,6 +630,8 @@ typedef int (*ssh_auth_callback) (const char *prompt, char *buf, size_t len, + int echo, int verify, void *userdata); + + LIBSSH_API ssh_key ssh_key_new(void); ++#define SSH_KEY_FREE(x) \ ++ do { if ((x) != NULL) { ssh_key_free(x); x = NULL; } } while(0) + LIBSSH_API void ssh_key_free (ssh_key key); + LIBSSH_API enum ssh_keytypes_e ssh_key_type(const ssh_key key); + LIBSSH_API const char *ssh_key_type_to_char(enum ssh_keytypes_e type); +diff --git a/src/messages.c b/src/messages.c +index 9ddfe15c..8733875c 100644 +--- a/src/messages.c ++++ b/src/messages.c +@@ -430,6 +430,13 @@ void ssh_message_queue(ssh_session session, ssh_message message){ + } + if (session->ssh_message_list != NULL) { + ssh_list_append(session->ssh_message_list, message); ++ } else { ++ /* If the message list couldn't be allocated, the message can't be ++ * enqueued */ ++ ssh_message_reply_default(message); ++ ssh_set_error_oom(session); ++ ssh_message_free(message); ++ return; + } + } + } +diff --git a/tests/client/torture_auth.c b/tests/client/torture_auth.c +index df7f2714..5f4a4ed8 100644 +--- a/tests/client/torture_auth.c ++++ b/tests/client/torture_auth.c +@@ -534,8 +534,8 @@ static void torture_auth_cert(void **state) { + rc = ssh_userauth_publickey(session, NULL, privkey); + assert_int_equal(rc, SSH_AUTH_SUCCESS); + +- ssh_key_free(privkey); +- ssh_key_free(cert); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(cert); + } + + static void torture_auth_agent_cert(void **state) { +diff --git a/tests/unittests/torture_buffer.c b/tests/unittests/torture_buffer.c +index 4d29a2a5..f5cb8f65 100644 +--- a/tests/unittests/torture_buffer.c ++++ b/tests/unittests/torture_buffer.c +@@ -22,7 +22,7 @@ static int setup(void **state) { + } + + static int teardown(void **state) { +- ssh_buffer_free(*state); ++ SSH_BUFFER_FREE(*state); + + return 0; + } +@@ -125,9 +125,9 @@ static void torture_ssh_buffer_get_ssh_string(void **state) { + for(l=0;lopts.wanted_methods[SSH_KEX], KEXALGORITHMS); + +@@ -223,14 +223,14 @@ static void torture_config_glob(void **state) { + assert_non_null(v); + + assert_string_equal(v, PROXYCMD); +- ssh_string_free_char(v); ++ SSH_STRING_FREE_CHAR(v); + + ret = ssh_options_get(session, SSH_OPTIONS_IDENTITY, &v); + assert_true(ret == 0); + assert_non_null(v); + + assert_string_equal(v, ID_FILE); +- ssh_string_free_char(v); ++ SSH_STRING_FREE_CHAR(v); + #endif /* HAVE_GLOB */ + } + +diff --git a/tests/unittests/torture_hashes.c b/tests/unittests/torture_hashes.c +index 104aa7c9..59e23d28 100644 +--- a/tests/unittests/torture_hashes.c ++++ b/tests/unittests/torture_hashes.c +@@ -41,88 +41,91 @@ static int setup_rsa_key(void **state) + + static int teardown(void **state) + { +- ssh_key_free(*state); ++ SSH_KEY_FREE(*state); + return 0; + } + + static void torture_md5_hash(void **state) + { + ssh_key pubkey = *state; +- unsigned char *hash = NULL; ++ char *hash = NULL; + char *hexa = NULL; + size_t hlen; + int rc = 0; + +- rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5, &hash, &hlen); ++ rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_MD5, ++ (unsigned char **)&hash, &hlen); + assert_true(rc == 0); + +- hexa = ssh_get_hexa(hash, hlen); +- ssh_string_free_char((char *)hash); ++ hexa = ssh_get_hexa((unsigned char *)hash, hlen); ++ SSH_STRING_FREE_CHAR(hash); + assert_string_equal(hexa, + "50:15:a0:9b:92:bf:33:1c:01:c5:8c:fe:18:fa:ce:78"); + +- ssh_string_free_char(hexa); ++ SSH_STRING_FREE_CHAR(hexa); + } + + static void torture_sha1_hash(void **state) + { + ssh_key pubkey = *state; +- unsigned char *hash = NULL; ++ char *hash = NULL; + char *sha1 = NULL; + int rc = 0; + size_t hlen; + +- rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA1, &hash, &hlen); ++ rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA1, ++ (unsigned char **)&hash, &hlen); + assert_true(rc == 0); + +- sha1 = ssh_get_b64_unpadded(hash, hlen); +- ssh_string_free_char((char *)hash); ++ sha1 = ssh_get_b64_unpadded((unsigned char *)hash, hlen); ++ SSH_STRING_FREE_CHAR(hash); + assert_string_equal(sha1, "6wP+houujQmxLBiFugTcoeoODCM"); + +- ssh_string_free_char(sha1); ++ SSH_STRING_FREE_CHAR(sha1); + } + + static void torture_sha256_hash(void **state) + { + ssh_key pubkey = *state; +- unsigned char *hash = NULL; ++ char *hash = NULL; + char *sha256 = NULL; + int rc = 0; + size_t hlen; + +- rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA256, &hash, &hlen); ++ rc = ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA256, ++ (unsigned char **)&hash, &hlen); + assert_true(rc == 0); + +- sha256 = ssh_get_b64_unpadded(hash, hlen); +- ssh_string_free_char((char *)hash); ++ sha256 = ssh_get_b64_unpadded((unsigned char *)hash, hlen); ++ SSH_STRING_FREE_CHAR(hash); + assert_string_equal(sha256, "jXstVLLe84fSDo1kEYGn6iumnPCSorhaiWxnJz8VTII"); + +- ssh_string_free_char(sha256); ++ SSH_STRING_FREE_CHAR(sha256); + + } + + static void torture_sha256_fingerprint(void **state) + { + ssh_key pubkey = *state; +- unsigned char *hash = NULL; ++ char *hash = NULL; + char *sha256 = NULL; + int rc = 0; + size_t hlen; + + rc = ssh_get_publickey_hash(pubkey, + SSH_PUBLICKEY_HASH_SHA256, +- &hash, ++ (unsigned char **)&hash, + &hlen); + assert_true(rc == 0); + + sha256 = ssh_get_fingerprint_hash(SSH_PUBLICKEY_HASH_SHA256, +- hash, ++ (unsigned char *)hash, + hlen); +- ssh_string_free_char(discard_const(hash)); ++ SSH_STRING_FREE_CHAR(hash); + assert_string_equal(sha256, + "SHA256:jXstVLLe84fSDo1kEYGn6iumnPCSorhaiWxnJz8VTII"); + +- ssh_string_free_char(sha256); ++ SSH_STRING_FREE_CHAR(sha256); + } + + int torture_run_tests(void) { +diff --git a/tests/unittests/torture_keyfiles.c b/tests/unittests/torture_keyfiles.c +index de924f00..59a4f5ee 100644 +--- a/tests/unittests/torture_keyfiles.c ++++ b/tests/unittests/torture_keyfiles.c +@@ -111,7 +111,7 @@ static void torture_pubkey_from_file(void **state) { + + assert_true(rc == 0); + +- ssh_string_free(pubkey); ++ SSH_STRING_FREE(pubkey); + + /* test if it returns 1 if pubkey doesn't exist */ + unlink(LIBSSH_RSA_TESTKEY ".pub"); +@@ -119,11 +119,17 @@ static void torture_pubkey_from_file(void **state) { + rc = ssh_try_publickey_from_file(session, LIBSSH_RSA_TESTKEY, &pubkey, &type); + assert_true(rc == 1); + ++ /* This free is unnecessary, but the static analyser does not know */ ++ SSH_STRING_FREE(pubkey); ++ + /* test if it returns -1 if privkey doesn't exist */ + unlink(LIBSSH_RSA_TESTKEY); + + rc = ssh_try_publickey_from_file(session, LIBSSH_RSA_TESTKEY, &pubkey, &type); + assert_true(rc == -1); ++ ++ /* This free is unnecessary, but the static analyser does not know */ ++ SSH_STRING_FREE(pubkey); + } + + static int torture_read_one_line(const char *filename, char *buffer, size_t len) { +@@ -210,8 +216,8 @@ static void torture_pubkey_generate_from_privkey(void **state) { + + assert_string_equal(pubkey_line_orig, pubkey_line_new); + +- ssh_string_free(pubkey_orig); +- ssh_string_free(pubkey_new); ++ SSH_STRING_FREE(pubkey_orig); ++ SSH_STRING_FREE(pubkey_new); + } + + /** +diff --git a/tests/unittests/torture_options.c b/tests/unittests/torture_options.c +index d9cd6e2a..7addce76 100644 +--- a/tests/unittests/torture_options.c ++++ b/tests/unittests/torture_options.c +@@ -560,7 +560,7 @@ static void torture_bind_options_import_key(void **state) + /* set invalid key */ + rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_IMPORT_KEY, key); + assert_int_equal(rc, -1); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + + /* set rsa key */ + base64_key = torture_get_testkey(SSH_KEYTYPE_RSA, 0, 0); +diff --git a/tests/unittests/torture_pki_dsa.c b/tests/unittests/torture_pki_dsa.c +index e8d03904..41ab9063 100644 +--- a/tests/unittests/torture_pki_dsa.c ++++ b/tests/unittests/torture_pki_dsa.c +@@ -82,7 +82,7 @@ static void torture_pki_dsa_import_pubkey_file(void **state) + assert_return_code(rc, errno); + assert_non_null(pubkey); + +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_dsa_import_pubkey_from_openssh_privkey(void **state) +@@ -97,7 +97,7 @@ static void torture_pki_dsa_import_pubkey_from_openssh_privkey(void **state) + assert_return_code(rc, errno); + assert_non_null(pubkey); + +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_dsa_import_privkey_base64(void **state) +@@ -115,7 +115,7 @@ static void torture_pki_dsa_import_privkey_base64(void **state) + &key); + assert_true(rc == 0); + +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + #ifdef HAVE_LIBCRYPTO +@@ -154,8 +154,8 @@ static void torture_pki_dsa_write_privkey(void **state) + rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + +- ssh_key_free(origkey); +- ssh_key_free(privkey); ++ SSH_KEY_FREE(origkey); ++ SSH_KEY_FREE(privkey); + + /* Test with passphrase */ + rc = ssh_pki_import_privkey_file(LIBSSH_DSA_TESTKEY_PASSPHRASE, +@@ -192,8 +192,8 @@ static void torture_pki_dsa_write_privkey(void **state) + rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + +- ssh_key_free(origkey); +- ssh_key_free(privkey); ++ SSH_KEY_FREE(origkey); ++ SSH_KEY_FREE(privkey); + } + #endif + +@@ -215,8 +215,7 @@ static void torture_pki_dsa_import_privkey_base64_passphrase(void **state) + rc = ssh_key_is_private(key); + assert_true(rc == 1); + +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + /* test if it returns -1 if passphrase is wrong */ + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_DSS, 0, 1), +@@ -247,8 +246,7 @@ static void torture_pki_dsa_import_privkey_base64_passphrase(void **state) + rc = ssh_key_is_private(key); + assert_true(rc == 1); + +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + /* test if it returns -1 if passphrase is wrong */ + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_DSS, 0, 1), +@@ -259,7 +257,7 @@ static void torture_pki_dsa_import_privkey_base64_passphrase(void **state) + assert_true(rc == -1); + + /* This free in unnecessary, but the static analyser does not know */ +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + + #ifndef HAVE_LIBCRYPTO + /* test if it returns -1 if passphrase is NULL */ +@@ -272,7 +270,7 @@ static void torture_pki_dsa_import_privkey_base64_passphrase(void **state) + assert_true(rc == -1); + + /* This free in unnecessary, but the static analyser does not know */ +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + #endif /* HAVE_LIBCRYPTO */ + } + +@@ -299,8 +297,7 @@ torture_pki_dsa_import_openssh_privkey_base64_passphrase(void **state) + rc = ssh_key_is_private(key); + assert_true(rc == 1); + +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + /* test if it returns -1 if passphrase is wrong */ + rc = ssh_pki_import_privkey_base64(keystring, +@@ -328,8 +325,7 @@ torture_pki_dsa_import_openssh_privkey_base64_passphrase(void **state) + rc = ssh_key_is_private(key); + assert_true(rc == 1); + +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + /* test if it returns -1 if passphrase is wrong */ + rc = ssh_pki_import_privkey_base64(keystring, +@@ -339,6 +335,9 @@ torture_pki_dsa_import_openssh_privkey_base64_passphrase(void **state) + &key); + assert_true(rc == -1); + ++ /* This free is unnecessary, but the static analyser does not know */ ++ SSH_KEY_FREE(key); ++ + /* test if it returns -1 if passphrase is NULL */ + rc = ssh_pki_import_privkey_base64(keystring, + NULL, +@@ -346,6 +345,9 @@ torture_pki_dsa_import_openssh_privkey_base64_passphrase(void **state) + NULL, + &key); + assert_true(rc == -1); ++ ++ /* This free is unnecessary, but the static analyser does not know */ ++ SSH_KEY_FREE(key); + } + + +@@ -371,8 +373,8 @@ static void torture_pki_dsa_publickey_from_privatekey(void **state) + rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey); + assert_true(rc == SSH_OK); + +- ssh_key_free(key); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(key); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_dsa_import_cert_file(void **state) +@@ -392,7 +394,7 @@ static void torture_pki_dsa_import_cert_file(void **state) + rc = ssh_key_is_public(cert); + assert_true(rc == 1); + +- ssh_key_free(cert); ++ SSH_KEY_FREE(cert); + } + + static void torture_pki_dsa_publickey_base64(void **state) +@@ -443,7 +445,7 @@ static void torture_pki_dsa_publickey_base64(void **state) + + free(b64_key); + free(key_buf); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + static void torture_pki_dsa_generate_pubkey_from_privkey(void **state) +@@ -482,8 +484,8 @@ static void torture_pki_dsa_generate_pubkey_from_privkey(void **state) + pubkey_generated, + len); + +- ssh_key_free(privkey); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_dsa_duplicate_key(void **state) +@@ -503,7 +505,7 @@ static void torture_pki_dsa_duplicate_key(void **state) + + rc = ssh_pki_export_pubkey_base64(pubkey, &b64_key); + assert_true(rc == 0); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + + rc = ssh_pki_import_privkey_file(LIBSSH_DSA_TESTKEY, + NULL, +@@ -530,11 +532,11 @@ static void torture_pki_dsa_duplicate_key(void **state) + rc = ssh_key_cmp(privkey, privkey_dup, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + +- ssh_key_free(pubkey); +- ssh_key_free(privkey); +- ssh_key_free(privkey_dup); +- ssh_string_free_char(b64_key); +- ssh_string_free_char(b64_key_gen); ++ SSH_KEY_FREE(pubkey); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(privkey_dup); ++ SSH_STRING_FREE_CHAR(b64_key); ++ SSH_STRING_FREE_CHAR(b64_key_gen); + } + + static void torture_pki_dsa_generate_key(void **state) +@@ -553,8 +555,7 @@ static void torture_pki_dsa_generate_key(void **state) + rc = pki_signature_verify(session,sign,key,DSA_HASH,20); + assert_true(rc == SSH_OK); + ssh_signature_free(sign); +- ssh_key_free(key); +- key=NULL; ++ SSH_KEY_FREE(key); + + rc = ssh_pki_generate(SSH_KEYTYPE_DSS, 2048, &key); + assert_true(rc == SSH_OK); +@@ -564,8 +565,7 @@ static void torture_pki_dsa_generate_key(void **state) + rc = pki_signature_verify(session,sign,key,DSA_HASH,20); + assert_true(rc == SSH_OK); + ssh_signature_free(sign); +- ssh_key_free(key); +- key=NULL; ++ SSH_KEY_FREE(key); + + rc = ssh_pki_generate(SSH_KEYTYPE_DSS, 3072, &key); + assert_true(rc == SSH_OK); +@@ -575,8 +575,7 @@ static void torture_pki_dsa_generate_key(void **state) + rc = pki_signature_verify(session,sign,key,DSA_HASH,20); + assert_true(rc == SSH_OK); + ssh_signature_free(sign); +- ssh_key_free(key); +- key=NULL; ++ SSH_KEY_FREE(key); + + ssh_free(session); + } +diff --git a/tests/unittests/torture_pki_ecdsa.c b/tests/unittests/torture_pki_ecdsa.c +index 497c7379..7ef354f7 100644 +--- a/tests/unittests/torture_pki_ecdsa.c ++++ b/tests/unittests/torture_pki_ecdsa.c +@@ -121,7 +121,7 @@ static void torture_pki_ecdsa_import_pubkey_file(void **state) + assert_return_code(rc, errno); + assert_non_null(pubkey); + +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_ecdsa_import_pubkey_from_openssh_privkey(void **state) +@@ -136,7 +136,7 @@ static void torture_pki_ecdsa_import_pubkey_from_openssh_privkey(void **state) + assert_return_code(rc, errno); + assert_non_null(pubkey); + +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_ecdsa_import_privkey_base64(void **state) +@@ -158,7 +158,7 @@ static void torture_pki_ecdsa_import_privkey_base64(void **state) + assert_true(rc == 1); + + free(key_str); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + static void torture_pki_ecdsa_publickey_from_privatekey(void **state) +@@ -181,8 +181,8 @@ static void torture_pki_ecdsa_publickey_from_privatekey(void **state) + assert_true(rc == SSH_OK); + + free(key_str); +- ssh_key_free(key); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(key); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_ecdsa_publickey_base64(void **state) +@@ -219,7 +219,7 @@ static void torture_pki_ecdsa_publickey_base64(void **state) + + free(b64_key); + free(key_buf); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + static void torture_pki_ecdsa_generate_pubkey_from_privkey(void **state) +@@ -261,8 +261,8 @@ static void torture_pki_ecdsa_generate_pubkey_from_privkey(void **state) + len = torture_pubkey_len(pubkey_original); + assert_int_equal(strncmp(pubkey_original, pubkey_generated, len), 0); + +- ssh_key_free(privkey); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_ecdsa_duplicate_key(void **state) +@@ -281,7 +281,7 @@ static void torture_pki_ecdsa_duplicate_key(void **state) + + rc = ssh_pki_export_pubkey_base64(pubkey, &b64_key); + assert_true(rc == 0); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + + rc = ssh_pki_import_privkey_file(LIBSSH_ECDSA_TESTKEY, + NULL, +@@ -307,11 +307,11 @@ static void torture_pki_ecdsa_duplicate_key(void **state) + rc = ssh_key_cmp(privkey, privkey_dup, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + +- ssh_key_free(pubkey); +- ssh_key_free(privkey); +- ssh_key_free(privkey_dup); +- ssh_string_free_char(b64_key); +- ssh_string_free_char(b64_key_gen); ++ SSH_KEY_FREE(pubkey); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(privkey_dup); ++ SSH_STRING_FREE_CHAR(b64_key); ++ SSH_STRING_FREE_CHAR(b64_key_gen); + } + + /* Test case for bug #147: Private ECDSA key duplication did not carry +@@ -342,9 +342,9 @@ static void torture_pki_ecdsa_duplicate_then_demote(void **state) + assert_true(rc == 0); + assert_int_equal(pubkey->ecdsa_nid, privkey->ecdsa_nid); + +- ssh_key_free(pubkey); +- ssh_key_free(privkey); +- ssh_key_free(privkey_dup); ++ SSH_KEY_FREE(pubkey); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(privkey_dup); + } + + static void torture_pki_generate_key_ecdsa(void **state) +@@ -373,8 +373,7 @@ static void torture_pki_generate_key_ecdsa(void **state) + assert_true(strcmp(etype_char, "ecdsa-sha2-nistp256") == 0); + + ssh_signature_free(sign); +- ssh_key_free(key); +- key=NULL; ++ SSH_KEY_FREE(key); + + rc = ssh_pki_generate(SSH_KEYTYPE_ECDSA, 384, &key); + assert_true(rc == SSH_OK); +@@ -391,8 +390,7 @@ static void torture_pki_generate_key_ecdsa(void **state) + assert_true(strcmp(etype_char, "ecdsa-sha2-nistp384") == 0); + + ssh_signature_free(sign); +- ssh_key_free(key); +- key=NULL; ++ SSH_KEY_FREE(key); + + rc = ssh_pki_generate(SSH_KEYTYPE_ECDSA, 512, &key); + assert_true(rc == SSH_OK); +@@ -409,8 +407,7 @@ static void torture_pki_generate_key_ecdsa(void **state) + assert_true(strcmp(etype_char, "ecdsa-sha2-nistp521") == 0); + + ssh_signature_free(sign); +- ssh_key_free(key); +- key=NULL; ++ SSH_KEY_FREE(key); + + ssh_free(session); + } +@@ -451,8 +448,8 @@ static void torture_pki_ecdsa_write_privkey(void **state) + rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + +- ssh_key_free(origkey); +- ssh_key_free(privkey); ++ SSH_KEY_FREE(origkey); ++ SSH_KEY_FREE(privkey); + + /* Test with passphrase */ + rc = ssh_pki_import_privkey_file(LIBSSH_ECDSA_TESTKEY_PASSPHRASE, +@@ -489,8 +486,8 @@ static void torture_pki_ecdsa_write_privkey(void **state) + rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + +- ssh_key_free(origkey); +- ssh_key_free(privkey); ++ SSH_KEY_FREE(origkey); ++ SSH_KEY_FREE(privkey); + } + #endif /* HAVE_LIBCRYPTO */ + +@@ -508,7 +505,7 @@ static void torture_pki_ecdsa_name(void **state, const char *expected_name) + etype_char =ssh_pki_key_ecdsa_name(key); + assert_true(strcmp(etype_char, expected_name) == 0); + +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + static void torture_pki_ecdsa_name256(void **state) +diff --git a/tests/unittests/torture_pki_ed25519.c b/tests/unittests/torture_pki_ed25519.c +index 39012168..a4b147bf 100644 +--- a/tests/unittests/torture_pki_ed25519.c ++++ b/tests/unittests/torture_pki_ed25519.c +@@ -62,7 +62,7 @@ static void torture_pki_ed25519_import_pubkey_file(void **state) + assert_return_code(rc, errno); + assert_non_null(pubkey); + +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_ed25519_import_pubkey_from_openssh_privkey(void **state) +@@ -77,7 +77,7 @@ static void torture_pki_ed25519_import_pubkey_from_openssh_privkey(void **state) + assert_return_code(rc, errno); + assert_non_null(pubkey); + +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_ed25519_import_privkey_base64(void **state) +@@ -106,7 +106,7 @@ static void torture_pki_ed25519_import_privkey_base64(void **state) + assert_true(rc == 1); + + free(key_str); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + + } + +@@ -141,7 +141,7 @@ static void torture_pki_ed25519_import_export_privkey_base64(void **state) + NULL, + &b64_key); + assert_return_code(rc, errno); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + + rc = ssh_pki_import_privkey_base64(b64_key, + passphrase, +@@ -157,7 +157,7 @@ static void torture_pki_ed25519_import_export_privkey_base64(void **state) + assert_true(rc == 1); + + SSH_STRING_FREE_CHAR(b64_key); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + static void torture_pki_ed25519_publickey_from_privatekey(void **state) +@@ -184,8 +184,8 @@ static void torture_pki_ed25519_publickey_from_privatekey(void **state) + rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey); + assert_true(rc == SSH_OK); + +- ssh_key_free(key); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(key); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_ed25519_publickey_base64(void **state) +@@ -222,7 +222,7 @@ static void torture_pki_ed25519_publickey_base64(void **state) + + free(b64_key); + free(key_buf); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + static void torture_pki_ed25519_generate_pubkey_from_privkey(void **state) +@@ -261,8 +261,8 @@ static void torture_pki_ed25519_generate_pubkey_from_privkey(void **state) + pubkey_generated, + len); + +- ssh_key_free(privkey); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_ed25519_generate_key(void **state) +@@ -293,8 +293,7 @@ static void torture_pki_ed25519_generate_key(void **state) + assert_true(rc == SSH_ERROR); + + ssh_signature_free(sign); +- ssh_key_free(key); +- key=NULL; ++ SSH_KEY_FREE(key); + + ssh_free(session); + } +@@ -336,7 +335,7 @@ static void torture_pki_ed25519_write_privkey(void **state) + assert_true(rc == 0); + + unlink(LIBSSH_ED25519_TESTKEY); +- ssh_key_free(privkey); ++ SSH_KEY_FREE(privkey); + /* do the same with passphrase */ + rc = ssh_pki_export_privkey_file(origkey, + torture_get_testkey_passphrase(), +@@ -365,8 +364,8 @@ static void torture_pki_ed25519_write_privkey(void **state) + assert_true(rc == 0); + unlink(LIBSSH_ED25519_TESTKEY); + +- ssh_key_free(origkey); +- ssh_key_free(privkey); ++ SSH_KEY_FREE(origkey); ++ SSH_KEY_FREE(privkey); + + /* Test with passphrase */ + rc = ssh_pki_import_privkey_file(LIBSSH_ED25519_TESTKEY_PASSPHRASE, +@@ -404,8 +403,8 @@ static void torture_pki_ed25519_write_privkey(void **state) + rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + +- ssh_key_free(origkey); +- ssh_key_free(privkey); ++ SSH_KEY_FREE(origkey); ++ SSH_KEY_FREE(privkey); + } + + static void torture_pki_ed25519_sign(void **state) +@@ -441,8 +440,8 @@ static void torture_pki_ed25519_sign(void **state) + assert_memory_equal(ssh_string_data(blob), ref_signature, sizeof(ref_signature)); + /* ssh_print_hexa("signature", ssh_string_data(blob), ssh_string_len(blob)); */ + ssh_signature_free(sig); +- ssh_key_free(privkey); +- ssh_string_free(blob); ++ SSH_KEY_FREE(privkey); ++ SSH_STRING_FREE(blob); + + } + +@@ -473,8 +472,8 @@ static void torture_pki_ed25519_verify(void **state){ + ssh_signature_free(sig); + /* alter signature and expect false result */ + +- ssh_key_free(pubkey); +- ssh_string_free(blob); ++ SSH_KEY_FREE(pubkey); ++ SSH_STRING_FREE(blob); + free(pkey_ptr); + } + +@@ -509,8 +508,8 @@ static void torture_pki_ed25519_verify_bad(void **state){ + ssh_signature_free(sig); + + } +- ssh_key_free(pubkey); +- ssh_string_free(blob); ++ SSH_KEY_FREE(pubkey); ++ SSH_STRING_FREE(blob); + free(pkey_ptr); + } + +@@ -535,8 +534,7 @@ static void torture_pki_ed25519_import_privkey_base64_passphrase(void **state) + rc = ssh_key_is_private(key); + assert_true(rc == 1); + +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + /* test if it returns -1 if passphrase is wrong */ + rc = ssh_pki_import_privkey_base64(testkey, +@@ -545,7 +543,7 @@ static void torture_pki_ed25519_import_privkey_base64_passphrase(void **state) + NULL, + &key); + assert_true(rc == -1); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + static void torture_pki_ed25519_privkey_dup(void **state) +@@ -572,8 +570,8 @@ static void torture_pki_ed25519_privkey_dup(void **state) + dup = ssh_key_dup(key); + assert_non_null(dup); + +- ssh_key_free(key); +- ssh_key_free(dup); ++ SSH_KEY_FREE(key); ++ SSH_KEY_FREE(dup); + } + + static void torture_pki_ed25519_pubkey_dup(void **state) +@@ -609,8 +607,8 @@ static void torture_pki_ed25519_pubkey_dup(void **state) + assert_true(rc == 1); + + SAFE_FREE(pub_str); +- ssh_key_free(pubkey); +- ssh_key_free(dup); ++ SSH_KEY_FREE(pubkey); ++ SSH_KEY_FREE(dup); + } + + int torture_run_tests(void) { +diff --git a/tests/unittests/torture_pki_rsa.c b/tests/unittests/torture_pki_rsa.c +index 0d5e97fa..15ad6466 100644 +--- a/tests/unittests/torture_pki_rsa.c ++++ b/tests/unittests/torture_pki_rsa.c +@@ -84,7 +84,7 @@ static void torture_pki_rsa_import_pubkey_file(void **state) + assert_return_code(rc, errno); + assert_non_null(pubkey); + +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_rsa_import_pubkey_from_openssh_privkey(void **state) +@@ -99,7 +99,7 @@ static void torture_pki_rsa_import_pubkey_from_openssh_privkey(void **state) + assert_return_code(rc, errno); + assert_non_null(pubkey); + +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_rsa_import_privkey_base64_NULL_key(void **state) +@@ -131,7 +131,7 @@ static void torture_pki_rsa_import_privkey_base64_NULL_str(void **state) + rc = ssh_pki_import_privkey_base64(NULL, passphrase, NULL, NULL, &key); + assert_true(rc == -1); + +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + static void torture_pki_rsa_import_privkey_base64(void **state) +@@ -160,7 +160,7 @@ static void torture_pki_rsa_import_privkey_base64(void **state) + assert_true(rc == 1); + + free(key_str); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + static void torture_pki_rsa_publickey_from_privatekey(void **state) +@@ -185,8 +185,8 @@ static void torture_pki_rsa_publickey_from_privatekey(void **state) + rc = ssh_pki_export_privkey_to_pubkey(key, &pubkey); + assert_true(rc == SSH_OK); + +- ssh_key_free(key); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(key); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_rsa_copy_cert_to_privkey(void **state) +@@ -239,9 +239,9 @@ static void torture_pki_rsa_copy_cert_to_privkey(void **state) + rc = ssh_pki_copy_cert_to_privkey(cert, privkey); + assert_true(rc == SSH_ERROR); + +- ssh_key_free(cert); +- ssh_key_free(privkey); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(cert); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_rsa_import_cert_file(void **state) { +@@ -260,7 +260,7 @@ static void torture_pki_rsa_import_cert_file(void **state) { + rc = ssh_key_is_public(cert); + assert_true(rc == 1); + +- ssh_key_free(cert); ++ SSH_KEY_FREE(cert); + } + + static void torture_pki_rsa_publickey_base64(void **state) +@@ -297,7 +297,7 @@ static void torture_pki_rsa_publickey_base64(void **state) + + free(b64_key); + free(key_buf); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + } + + static void torture_pki_rsa_generate_pubkey_from_privkey(void **state) { +@@ -335,8 +335,8 @@ static void torture_pki_rsa_generate_pubkey_from_privkey(void **state) { + pubkey_generated, + len); + +- ssh_key_free(privkey); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(pubkey); + } + + static void torture_pki_rsa_duplicate_key(void **state) +@@ -356,7 +356,7 @@ static void torture_pki_rsa_duplicate_key(void **state) + + rc = ssh_pki_export_pubkey_base64(pubkey, &b64_key); + assert_true(rc == 0); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + + rc = ssh_pki_import_privkey_file(LIBSSH_RSA_TESTKEY, + NULL, +@@ -382,11 +382,11 @@ static void torture_pki_rsa_duplicate_key(void **state) + rc = ssh_key_cmp(privkey, privkey_dup, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + +- ssh_key_free(pubkey); +- ssh_key_free(privkey); +- ssh_key_free(privkey_dup); +- ssh_string_free_char(b64_key); +- ssh_string_free_char(b64_key_gen); ++ SSH_KEY_FREE(pubkey); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(privkey_dup); ++ SSH_STRING_FREE_CHAR(b64_key); ++ SSH_STRING_FREE_CHAR(b64_key_gen); + } + + static void torture_pki_rsa_generate_key(void **state) +@@ -405,7 +405,7 @@ static void torture_pki_rsa_generate_key(void **state) + rc = pki_signature_verify(session,sign,key,RSA_HASH,20); + assert_true(rc == SSH_OK); + ssh_signature_free(sign); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + key=NULL; + + rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &key); +@@ -416,7 +416,7 @@ static void torture_pki_rsa_generate_key(void **state) + rc = pki_signature_verify(session,sign,key,RSA_HASH,20); + assert_true(rc == SSH_OK); + ssh_signature_free(sign); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + key=NULL; + + rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 4096, &key); +@@ -427,7 +427,7 @@ static void torture_pki_rsa_generate_key(void **state) + rc = pki_signature_verify(session,sign,key,RSA_HASH,20); + assert_true(rc == SSH_OK); + ssh_signature_free(sign); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + key=NULL; + + ssh_free(session); +@@ -477,7 +477,7 @@ static void torture_pki_rsa_sha2(void **state) + ssh_signature_free(sign); + + /* Cleanup */ +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + ssh_free(session); + } + +@@ -518,8 +518,8 @@ static void torture_pki_rsa_write_privkey(void **state) + rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + +- ssh_key_free(origkey); +- ssh_key_free(privkey); ++ SSH_KEY_FREE(origkey); ++ SSH_KEY_FREE(privkey); + + /* Test with passphrase */ + rc = ssh_pki_import_privkey_file(LIBSSH_RSA_TESTKEY_PASSPHRASE, +@@ -557,8 +557,8 @@ static void torture_pki_rsa_write_privkey(void **state) + rc = ssh_key_cmp(origkey, privkey, SSH_KEY_CMP_PRIVATE); + assert_true(rc == 0); + +- ssh_key_free(origkey); +- ssh_key_free(privkey); ++ SSH_KEY_FREE(origkey); ++ SSH_KEY_FREE(privkey); + } + #endif /* HAVE_LIBCRYPTO */ + +@@ -581,8 +581,7 @@ static void torture_pki_rsa_import_privkey_base64_passphrase(void **state) + rc = ssh_key_is_private(key); + assert_true(rc == 1); + +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + /* test if it returns -1 if passphrase is wrong */ + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_RSA, 0, 1), +@@ -591,8 +590,7 @@ static void torture_pki_rsa_import_privkey_base64_passphrase(void **state) + NULL, + &key); + assert_true(rc == -1); +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + #ifndef HAVE_LIBCRYPTO + /* test if it returns -1 if passphrase is NULL */ +@@ -603,8 +601,7 @@ static void torture_pki_rsa_import_privkey_base64_passphrase(void **state) + NULL, + &key); + assert_true(rc == -1); +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + #endif + } + +@@ -631,8 +628,7 @@ torture_pki_rsa_import_openssh_privkey_base64_passphrase(void **state) + rc = ssh_key_is_private(key); + assert_true(rc == 1); + +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + /* test if it returns -1 if passphrase is wrong */ + rc = ssh_pki_import_privkey_base64(keystring, +@@ -641,8 +637,7 @@ torture_pki_rsa_import_openssh_privkey_base64_passphrase(void **state) + NULL, + &key); + assert_true(rc == -1); +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + /* test if it returns -1 if passphrase is NULL */ + /* libcrypto asks for a passphrase, so skip this test */ +@@ -652,8 +647,7 @@ torture_pki_rsa_import_openssh_privkey_base64_passphrase(void **state) + NULL, + &key); + assert_true(rc == -1); +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + } + + int torture_run_tests(void) { +diff --git a/tests/unittests/torture_threads_buffer.c b/tests/unittests/torture_threads_buffer.c +index e3cebdc9..2e6f30b6 100644 +--- a/tests/unittests/torture_threads_buffer.c ++++ b/tests/unittests/torture_threads_buffer.c +@@ -87,7 +87,7 @@ static void *thread_growing_buffer(void *threadid) + } + + /* Teardown */ +- ssh_buffer_free(buffer); ++ SSH_BUFFER_FREE(buffer); + pthread_exit(NULL); + } + +@@ -134,14 +134,14 @@ static void *thread_growing_buffer_shifting(void *threadid) + if (ssh_buffer_get_len(buffer) * 4 < buffer->allocated) { + assert_true(ssh_buffer_get_len(buffer) * 4 >= buffer->allocated); + /* Teardown */ +- ssh_buffer_free(buffer); ++ SSH_BUFFER_FREE(buffer); + pthread_exit(NULL); + } + } + } + + /* Teardown */ +- ssh_buffer_free(buffer); ++ SSH_BUFFER_FREE(buffer); + pthread_exit(NULL); + } + +@@ -198,7 +198,7 @@ static void *thread_buffer_prepend(void *threadid) + assert_memory_equal(ssh_buffer_get(buffer), "12345bcdef", 10); + + /* Teardown */ +- ssh_buffer_free(buffer); ++ SSH_BUFFER_FREE(buffer); + pthread_exit(NULL); + } + +@@ -247,9 +247,9 @@ static void *thread_ssh_buffer_get_ssh_string(void *threadid) + for (l = 0; l < k; ++l) { + ssh_string str = ssh_buffer_get_ssh_string(buffer); + assert_null(str); +- ssh_string_free(str); ++ SSH_STRING_FREE(str); + } +- ssh_buffer_free(buffer); ++ SSH_BUFFER_FREE(buffer); + } + } + } +@@ -316,10 +316,10 @@ static void *thread_ssh_buffer_add_format(void *threadid) + assert_int_equal(len, sizeof(verif) - 1); + assert_memory_equal(ssh_buffer_get(buffer), verif, sizeof(verif) -1); + +- ssh_string_free(s); ++ SSH_STRING_FREE(s); + + /* Teardown */ +- ssh_buffer_free(buffer); ++ SSH_BUFFER_FREE(buffer); + pthread_exit(NULL); + } + +@@ -397,7 +397,7 @@ static void *thread_ssh_buffer_get_format(void *threadid) { + SAFE_FREE(s2); + + /* Teardown */ +- ssh_buffer_free(buffer); ++ SSH_BUFFER_FREE(buffer); + pthread_exit(NULL); + } + +@@ -458,7 +458,7 @@ static void *thread_ssh_buffer_get_format_error(void *threadid) + assert_true(s2 == NULL); + + /* Teardown */ +- ssh_buffer_free(buffer); ++ SSH_BUFFER_FREE(buffer); + pthread_exit(NULL); + } + +@@ -514,7 +514,7 @@ static void *thread_buffer_pack_badformat(void *threadid) + * it could crash the process */ + + /* Teardown */ +- ssh_buffer_free(buffer); ++ SSH_BUFFER_FREE(buffer); + pthread_exit(NULL); + } + +diff --git a/tests/unittests/torture_threads_pki_rsa.c b/tests/unittests/torture_threads_pki_rsa.c +index d19d8bbf..1313f566 100644 +--- a/tests/unittests/torture_threads_pki_rsa.c ++++ b/tests/unittests/torture_threads_pki_rsa.c +@@ -143,7 +143,7 @@ static void *thread_pki_rsa_import_pubkey_file(void *threadid) + assert_return_code(rc, errno); + assert_non_null(pubkey); + +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + + pthread_exit(NULL); + } +@@ -201,7 +201,7 @@ static void *thread_pki_rsa_import_privkey_base64_NULL_str(void *threadid) + rc = ssh_pki_import_privkey_base64(NULL, passphrase, NULL, NULL, &key); + assert_true(rc == -1); + +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + pthread_exit(NULL); + } + +@@ -242,7 +242,7 @@ static void *thread_pki_rsa_import_privkey_base64(void *threadid) + assert_true(ok); + + free(key_str); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + + pthread_exit(NULL); + } +@@ -283,8 +283,8 @@ static void *thread_pki_rsa_publickey_from_privatekey(void *threadid) + assert_true(rc == SSH_OK); + assert_non_null(pubkey); + +- ssh_key_free(key); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(key); ++ SSH_KEY_FREE(pubkey); + pthread_exit(NULL); + } + +@@ -349,9 +349,9 @@ static void *thread_pki_rsa_copy_cert_to_privkey(void *threadid) + rc = ssh_pki_copy_cert_to_privkey(cert, privkey); + assert_true(rc == SSH_ERROR); + +- ssh_key_free(cert); +- ssh_key_free(privkey); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(cert); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(pubkey); + pthread_exit(NULL); + } + +@@ -383,7 +383,7 @@ static void *thread_pki_rsa_import_cert_file(void *threadid) + rc = ssh_key_is_public(cert); + assert_true(rc == 1); + +- ssh_key_free(cert); ++ SSH_KEY_FREE(cert); + pthread_exit(NULL); + } + +@@ -432,7 +432,7 @@ static void *thread_pki_rsa_publickey_base64(void *threadid) + + free(b64_key); + free(key_buf); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + pthread_exit(NULL); + } + +@@ -464,7 +464,7 @@ static void *thread_pki_rsa_duplicate_key(void *threadid) + + rc = ssh_pki_export_pubkey_base64(pubkey, &b64_key); + assert_true(rc == 0); +- ssh_key_free(pubkey); ++ SSH_KEY_FREE(pubkey); + + rc = ssh_pki_import_privkey_file(LIBSSH_RSA_TESTKEY, + NULL, +@@ -489,11 +489,11 @@ static void *thread_pki_rsa_duplicate_key(void *threadid) + cmp = ssh_key_cmp(privkey, privkey_dup, SSH_KEY_CMP_PRIVATE); + assert_true(cmp == 0); + +- ssh_key_free(pubkey); +- ssh_key_free(privkey); +- ssh_key_free(privkey_dup); +- ssh_string_free_char(b64_key); +- ssh_string_free_char(b64_key_gen); ++ SSH_KEY_FREE(pubkey); ++ SSH_KEY_FREE(privkey); ++ SSH_KEY_FREE(privkey_dup); ++ SSH_STRING_FREE_CHAR(b64_key); ++ SSH_STRING_FREE_CHAR(b64_key_gen); + pthread_exit(NULL); + } + +@@ -531,8 +531,7 @@ static void *thread_pki_rsa_generate_key(void *threadid) + assert_ssh_return_code(session, rc); + + ssh_signature_free(sign); +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &key); + assert_ssh_return_code(session, rc); +@@ -545,8 +544,7 @@ static void *thread_pki_rsa_generate_key(void *threadid) + assert_ssh_return_code(session, rc); + + ssh_signature_free(sign); +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + + rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 4096, &key); +@@ -560,7 +558,7 @@ static void *thread_pki_rsa_generate_key(void *threadid) + assert_true(rc == SSH_OK); + + ssh_signature_free(sign); +- ssh_key_free(key); ++ SSH_KEY_FREE(key); + key = NULL; + + ssh_free(session); +@@ -596,8 +594,7 @@ static void *thread_pki_rsa_import_privkey_base64_passphrase(void *threadid) + rc = ssh_key_is_private(key); + assert_true(rc == 1); + +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + /* test if it returns -1 if passphrase is wrong */ + rc = ssh_pki_import_privkey_base64(torture_get_testkey(SSH_KEYTYPE_RSA, 0, 1), +@@ -606,8 +603,7 @@ static void *thread_pki_rsa_import_privkey_base64_passphrase(void *threadid) + NULL, + &key); + assert_true(rc == -1); +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + + #ifndef HAVE_LIBCRYPTO + /* test if it returns -1 if passphrase is NULL */ +@@ -618,8 +614,7 @@ static void *thread_pki_rsa_import_privkey_base64_passphrase(void *threadid) + NULL, + &key); + assert_true(rc == -1); +- ssh_key_free(key); +- key = NULL; ++ SSH_KEY_FREE(key); + #endif + pthread_exit(NULL); + } diff --git a/libssh-0.8.3.tar.xz b/libssh-0.8.3.tar.xz new file mode 100644 index 0000000..8ed3e5f Binary files /dev/null and b/libssh-0.8.3.tar.xz differ diff --git a/libssh-0.8.3.tar.xz.asc b/libssh-0.8.3.tar.xz.asc new file mode 100644 index 0000000..9b0543f --- /dev/null +++ b/libssh-0.8.3.tar.xz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEEjf9T4Y8qvI2PPJIjfuD8TcwBTj0FAlukpGkACgkQfuD8TcwB +Tj3qsA//bPS3hYBbKIChg1+o2s/lAbkjV6mv5LR9gyTljjUAikFNf/AN/yrNLD/H +0sAAD8S2Mj5t4+daUronpX9IJPZtimFB3WoBl+S9J9ybyzpgsspTNv0KZt/O9Vt+ +QamOYkMXDtDcqUCHxIzURKiIc6ATsobiUx6EhWOSa8fFsnW6golCJtHzHi5fKsPF +x92J5gZ4jUehZJEiX/LmqFCblLK5qV8g/F+TauWg9jL5m0SNuR0gfDxi3VNV+yeG +gCtneHNrg/Jq9PwI71dIAQ+EDxYARBrLRe7zNSJgZHNuHttyVZaObgO/tFGzAwfj +g+9cuBTHvkKbgM0CodT9ftmdXU8Gt2/3yugfP/FSHUKCy9YgOM5Yo+T8lhAw3Pnt +5ZienZztJwBabui7rWeebhaBSFNuaFUhp1V5HOBT1YjKWlr3yqSGs2PmYYA7Ioeq +ulcyUsNZFXj7hALCxhyBfcwz+USWBpjuxZz5gK5uXbwWcxZUkiRTCXprKiN8jUn/ +1/wteO4inm3dpKM3oMuxsk6c64JZnbXkD9vPEP7Fv48nPVVcqs+jk5RPK7iOBUgd +bglc6F05cnUzFz78Lj/FIgEqdYV/vGtxxpwOCRPBDhDWvjbDltN7GkcKQ7ItNd9L +UpMir12LL1Lo32IWxH457dKSCut2/+wGGLcXjUMMhhs/6UDqerg= +=uDol +-----END PGP SIGNATURE----- diff --git a/libssh-stable-0p8-CVE-2018-10933-part1.patch b/libssh-stable-0p8-CVE-2018-10933-part1.patch new file mode 100644 index 0000000..1a60e73 --- /dev/null +++ b/libssh-stable-0p8-CVE-2018-10933-part1.patch @@ -0,0 +1,130 @@ +From b166ac4749c78f475b1708f0345e6ca2749c5d6d Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Mon, 10 Sep 2018 17:37:42 +0200 +Subject: CVE-2018-10933: Introduced new auth states + +Introduced the states SSH_AUTH_STATE_PUBKEY_OFFER_SENT and +SSH_AUTH_STATE_PUBKEY_AUTH_SENT to know when SSH2_MSG_USERAUTH_PK_OK and +SSH2_MSG_USERAUTH_SUCCESS should be expected. + +Fixes T101 + +Signed-off-by: Anderson Toshiyuki Sasaki +Reviewed-by: Andreas Schneider +--- + include/libssh/auth.h | 4 ++++ + src/auth.c | 44 +++++++++++++++++++++++++++----------------- + 2 files changed, 31 insertions(+), 17 deletions(-) + +diff --git a/include/libssh/auth.h b/include/libssh/auth.h +index 3913f219..8daab47d 100644 +--- a/include/libssh/auth.h ++++ b/include/libssh/auth.h +@@ -76,6 +76,10 @@ enum ssh_auth_state_e { + SSH_AUTH_STATE_GSSAPI_TOKEN, + /** We have sent the MIC and expecting to be authenticated */ + SSH_AUTH_STATE_GSSAPI_MIC_SENT, ++ /** We have offered a pubkey to check if it is supported */ ++ SSH_AUTH_STATE_PUBKEY_OFFER_SENT, ++ /** We have sent pubkey and signature expecting to be authenticated */ ++ SSH_AUTH_STATE_PUBKEY_AUTH_SENT, + }; + + /** @internal +diff --git a/src/auth.c b/src/auth.c +index 97b6a6e1..41b76aa6 100644 +--- a/src/auth.c ++++ b/src/auth.c +@@ -85,6 +85,8 @@ static int ssh_auth_response_termination(void *user) { + case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT: + case SSH_AUTH_STATE_GSSAPI_TOKEN: + case SSH_AUTH_STATE_GSSAPI_MIC_SENT: ++ case SSH_AUTH_STATE_PUBKEY_AUTH_SENT: ++ case SSH_AUTH_STATE_PUBKEY_OFFER_SENT: + return 0; + default: + return 1; +@@ -167,6 +169,8 @@ static int ssh_userauth_get_response(ssh_session session) { + case SSH_AUTH_STATE_GSSAPI_REQUEST_SENT: + case SSH_AUTH_STATE_GSSAPI_TOKEN: + case SSH_AUTH_STATE_GSSAPI_MIC_SENT: ++ case SSH_AUTH_STATE_PUBKEY_OFFER_SENT: ++ case SSH_AUTH_STATE_PUBKEY_AUTH_SENT: + case SSH_AUTH_STATE_NONE: + /* not reached */ + rc = SSH_AUTH_ERROR; +@@ -312,24 +316,30 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_success) { + SSH_PACKET_CALLBACK(ssh_packet_userauth_pk_ok) { + int rc; + +- SSH_LOG(SSH_LOG_TRACE, "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE"); +- +- if (session->auth.state == SSH_AUTH_STATE_KBDINT_SENT) { +- /* Assuming we are in keyboard-interactive context */ + SSH_LOG(SSH_LOG_TRACE, +- "keyboard-interactive context, assuming SSH_USERAUTH_INFO_REQUEST"); +- rc = ssh_packet_userauth_info_request(session,type,packet,user); ++ "Received SSH_USERAUTH_PK_OK/INFO_REQUEST/GSSAPI_RESPONSE"); ++ ++ if (session->auth.state == SSH_AUTH_STATE_KBDINT_SENT) { ++ /* Assuming we are in keyboard-interactive context */ ++ SSH_LOG(SSH_LOG_TRACE, ++ "keyboard-interactive context, " ++ "assuming SSH_USERAUTH_INFO_REQUEST"); ++ rc = ssh_packet_userauth_info_request(session,type,packet,user); + #ifdef WITH_GSSAPI +- } else if (session->auth.state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT) { +- rc = ssh_packet_userauth_gssapi_response(session, type, packet, user); ++ } else if (session->auth.state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT) { ++ rc = ssh_packet_userauth_gssapi_response(session, type, packet, user); + #endif +- } else { +- session->auth.state = SSH_AUTH_STATE_PK_OK; +- SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK"); +- rc = SSH_PACKET_USED; +- } ++ } else if (session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT) { ++ session->auth.state = SSH_AUTH_STATE_PK_OK; ++ SSH_LOG(SSH_LOG_TRACE, "Assuming SSH_USERAUTH_PK_OK"); ++ rc = SSH_PACKET_USED; ++ } else { ++ session->auth.state = SSH_AUTH_STATE_ERROR; ++ SSH_LOG(SSH_LOG_TRACE, "SSH_USERAUTH_PK_OK received in wrong state"); ++ rc = SSH_PACKET_USED; ++ } + +- return rc; ++ return rc; + } + + /** +@@ -553,7 +563,7 @@ int ssh_userauth_try_publickey(ssh_session session, + ssh_string_free(pubkey_s); + + session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY; +- session->auth.state = SSH_AUTH_STATE_NONE; ++ session->auth.state = SSH_AUTH_STATE_PUBKEY_OFFER_SENT; + session->pending_call_state = SSH_PENDING_CALL_AUTH_OFFER_PUBKEY; + rc = ssh_packet_send(session); + if (rc == SSH_ERROR) { +@@ -701,7 +711,7 @@ int ssh_userauth_publickey(ssh_session session, + } + + session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY; +- session->auth.state = SSH_AUTH_STATE_NONE; ++ session->auth.state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT; + session->pending_call_state = SSH_PENDING_CALL_AUTH_PUBKEY; + rc = ssh_packet_send(session); + if (rc == SSH_ERROR) { +@@ -797,7 +807,7 @@ static int ssh_userauth_agent_publickey(ssh_session session, + } + + session->auth.current_method = SSH_AUTH_METHOD_PUBLICKEY; +- session->auth.state = SSH_AUTH_STATE_NONE; ++ session->auth.state = SSH_AUTH_STATE_PUBKEY_AUTH_SENT; + session->pending_call_state = SSH_PENDING_CALL_AUTH_AGENT; + rc = ssh_packet_send(session); + if (rc == SSH_ERROR) { +-- +cgit v1.2.1 + diff --git a/libssh-stable-0p8-CVE-2018-10933-part2.patch b/libssh-stable-0p8-CVE-2018-10933-part2.patch new file mode 100644 index 0000000..de530b9 --- /dev/null +++ b/libssh-stable-0p8-CVE-2018-10933-part2.patch @@ -0,0 +1,62 @@ +From fcfba0d8aa15a0142e57513f271eb7fa4bbabc9a Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Mon, 10 Sep 2018 17:38:22 +0200 +Subject: CVE-2018-10933: Introduce SSH_AUTH_STATE_PASSWORD_AUTH_SENT + +The introduced auth state allows to identify when authentication using +password was tried. + +Fixes T101 + +Signed-off-by: Anderson Toshiyuki Sasaki +Reviewed-by: Andreas Schneider +--- + include/libssh/auth.h | 2 ++ + src/auth.c | 4 +++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/include/libssh/auth.h b/include/libssh/auth.h +index 8daab47d..899282c1 100644 +--- a/include/libssh/auth.h ++++ b/include/libssh/auth.h +@@ -80,6 +80,8 @@ enum ssh_auth_state_e { + SSH_AUTH_STATE_PUBKEY_OFFER_SENT, + /** We have sent pubkey and signature expecting to be authenticated */ + SSH_AUTH_STATE_PUBKEY_AUTH_SENT, ++ /** We have sent a password expecting to be authenticated */ ++ SSH_AUTH_STATE_PASSWORD_AUTH_SENT, + }; + + /** @internal +diff --git a/src/auth.c b/src/auth.c +index 41b76aa6..2b06d2e1 100644 +--- a/src/auth.c ++++ b/src/auth.c +@@ -87,6 +87,7 @@ static int ssh_auth_response_termination(void *user) { + case SSH_AUTH_STATE_GSSAPI_MIC_SENT: + case SSH_AUTH_STATE_PUBKEY_AUTH_SENT: + case SSH_AUTH_STATE_PUBKEY_OFFER_SENT: ++ case SSH_AUTH_STATE_PASSWORD_AUTH_SENT: + return 0; + default: + return 1; +@@ -171,6 +172,7 @@ static int ssh_userauth_get_response(ssh_session session) { + case SSH_AUTH_STATE_GSSAPI_MIC_SENT: + case SSH_AUTH_STATE_PUBKEY_OFFER_SENT: + case SSH_AUTH_STATE_PUBKEY_AUTH_SENT: ++ case SSH_AUTH_STATE_PASSWORD_AUTH_SENT: + case SSH_AUTH_STATE_NONE: + /* not reached */ + rc = SSH_AUTH_ERROR; +@@ -1268,7 +1270,7 @@ int ssh_userauth_password(ssh_session session, + } + + session->auth.current_method = SSH_AUTH_METHOD_PASSWORD; +- session->auth.state = SSH_AUTH_STATE_NONE; ++ session->auth.state = SSH_AUTH_STATE_PASSWORD_AUTH_SENT; + session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD; + rc = ssh_packet_send(session); + if (rc == SSH_ERROR) { +-- +cgit v1.2.1 + diff --git a/libssh-stable-0p8-CVE-2018-10933-part3.patch b/libssh-stable-0p8-CVE-2018-10933-part3.patch new file mode 100644 index 0000000..e70e5e7 --- /dev/null +++ b/libssh-stable-0p8-CVE-2018-10933-part3.patch @@ -0,0 +1,62 @@ +From 7819621fc2a07d2d4649b36ca77850610741cfec Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Wed, 19 Sep 2018 17:01:15 +0200 +Subject: CVE-2018-10933: Introduce SSH_AUTH_STATE_AUTH_NONE_SENT + +The introduced auth state allows to identify when a request without +authentication information was sent. + +Fixes T101 + +Signed-off-by: Anderson Toshiyuki Sasaki +Reviewed-by: Andreas Schneider +--- + include/libssh/auth.h | 2 ++ + src/auth.c | 4 +++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/include/libssh/auth.h b/include/libssh/auth.h +index 899282c1..90b377d4 100644 +--- a/include/libssh/auth.h ++++ b/include/libssh/auth.h +@@ -82,6 +82,8 @@ enum ssh_auth_state_e { + SSH_AUTH_STATE_PUBKEY_AUTH_SENT, + /** We have sent a password expecting to be authenticated */ + SSH_AUTH_STATE_PASSWORD_AUTH_SENT, ++ /** We have sent a request without auth information (method 'none') */ ++ SSH_AUTH_STATE_AUTH_NONE_SENT, + }; + + /** @internal +diff --git a/src/auth.c b/src/auth.c +index 2b06d2e1..993e6dfe 100644 +--- a/src/auth.c ++++ b/src/auth.c +@@ -88,6 +88,7 @@ static int ssh_auth_response_termination(void *user) { + case SSH_AUTH_STATE_PUBKEY_AUTH_SENT: + case SSH_AUTH_STATE_PUBKEY_OFFER_SENT: + case SSH_AUTH_STATE_PASSWORD_AUTH_SENT: ++ case SSH_AUTH_STATE_AUTH_NONE_SENT: + return 0; + default: + return 1; +@@ -173,6 +174,7 @@ static int ssh_userauth_get_response(ssh_session session) { + case SSH_AUTH_STATE_PUBKEY_OFFER_SENT: + case SSH_AUTH_STATE_PUBKEY_AUTH_SENT: + case SSH_AUTH_STATE_PASSWORD_AUTH_SENT: ++ case SSH_AUTH_STATE_AUTH_NONE_SENT: + case SSH_AUTH_STATE_NONE: + /* not reached */ + rc = SSH_AUTH_ERROR; +@@ -428,7 +430,7 @@ int ssh_userauth_none(ssh_session session, const char *username) { + } + + session->auth.current_method = SSH_AUTH_METHOD_NONE; +- session->auth.state = SSH_AUTH_STATE_NONE; ++ session->auth.state = SSH_AUTH_STATE_AUTH_NONE_SENT; + session->pending_call_state = SSH_PENDING_CALL_AUTH_NONE; + rc = ssh_packet_send(session); + if (rc == SSH_ERROR) { +-- +cgit v1.2.1 + diff --git a/libssh-stable-0p8-CVE-2018-10933-part4.patch b/libssh-stable-0p8-CVE-2018-10933-part4.patch new file mode 100644 index 0000000..6a9a6ed --- /dev/null +++ b/libssh-stable-0p8-CVE-2018-10933-part4.patch @@ -0,0 +1,34 @@ +From 72bce5ece7edc2fd8023185f9d47b9fc86ef4663 Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Wed, 5 Sep 2018 12:14:07 +0200 +Subject: CVE-2018-10933: Set correct state after sending MIC + +After sending the client token, the auth state is set as +SSH_AUTH_STATE_GSSAPI_MIC_SENT. Then this can be expected to be the +state when a USERAUTH_FAILURE or USERAUTH_SUCCESS arrives. + +Fixes T101 + +Signed-off-by: Anderson Toshiyuki Sasaki +Reviewed-by: Andreas Schneider +--- + src/gssapi.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/gssapi.c b/src/gssapi.c +index 51b69e7a..77df0b59 100644 +--- a/src/gssapi.c ++++ b/src/gssapi.c +@@ -960,8 +960,8 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_gssapi_token_client){ + } + + if (maj_stat == GSS_S_COMPLETE) { +- session->auth.state = SSH_AUTH_STATE_NONE; + ssh_gssapi_send_mic(session); ++ session->auth.state = SSH_AUTH_STATE_GSSAPI_MIC_SENT; + } + + return SSH_PACKET_USED; +-- +cgit v1.2.1 + diff --git a/libssh-stable-0p8-CVE-2018-10933-part5.patch b/libssh-stable-0p8-CVE-2018-10933-part5.patch new file mode 100644 index 0000000..91c73aa --- /dev/null +++ b/libssh-stable-0p8-CVE-2018-10933-part5.patch @@ -0,0 +1,39 @@ +From adeaa69cc535827ec8acfbaf3ff91224b5a595a7 Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Fri, 7 Sep 2018 17:00:40 +0200 +Subject: CVE-2018-10933: Check channel state when OPEN_CONFIRMATION arrives + +When a SSH2_MSG_OPEN_CONFIRMATION arrives, the channel state is checked +to be in SSH_CHANNEL_STATE_OPENING. + +Fixes T101 + +Signed-off-by: Anderson Toshiyuki Sasaki +Reviewed-by: Andreas Schneider +--- + src/channels.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/src/channels.c b/src/channels.c +index 103009a8..b26f6bd4 100644 +--- a/src/channels.c ++++ b/src/channels.c +@@ -171,6 +171,15 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_conf){ + "Received a CHANNEL_OPEN_CONFIRMATION for channel %d:%d", + channel->local_channel, + channel->remote_channel); ++ ++ if (channel->state != SSH_CHANNEL_STATE_OPENING) { ++ SSH_LOG(SSH_LOG_RARE, ++ "SSH2_MSG_CHANNEL_OPEN_CONFIRMATION received in incorrect " ++ "channel state %d", ++ channel->state); ++ goto error; ++ } ++ + SSH_LOG(SSH_LOG_PROTOCOL, + "Remote window : %lu, maxpacket : %lu", + (long unsigned int) channel->remote_window, +-- +cgit v1.2.1 + diff --git a/libssh-stable-0p8-CVE-2018-10933-part6.patch b/libssh-stable-0p8-CVE-2018-10933-part6.patch new file mode 100644 index 0000000..b25cc88 --- /dev/null +++ b/libssh-stable-0p8-CVE-2018-10933-part6.patch @@ -0,0 +1,49 @@ +From f8c452cbef228b105dcb757d7554c3388a4dbea5 Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Fri, 7 Sep 2018 17:12:01 +0200 +Subject: CVE-2018-10933: Check channel state when OPEN_FAILURE arrives + +When a SSH2_MSG_OPEN_FAILURE arrives, the channel state is checked +to be in SSH_CHANNEL_STATE_OPENING. + +Fixes T101 + +Signed-off-by: Anderson Toshiyuki Sasaki +Reviewed-by: Andreas Schneider +--- + src/channels.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/src/channels.c b/src/channels.c +index b26f6bd4..0e61e5cd 100644 +--- a/src/channels.c ++++ b/src/channels.c +@@ -220,6 +220,14 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){ + return SSH_PACKET_USED; + } + ++ if (channel->state != SSH_CHANNEL_STATE_OPENING) { ++ SSH_LOG(SSH_LOG_RARE, ++ "SSH2_MSG_CHANNEL_OPEN_FAILURE received in incorrect channel " ++ "state %d", ++ channel->state); ++ goto error; ++ } ++ + ssh_set_error(session, SSH_REQUEST_DENIED, + "Channel opening failure: channel %u error (%lu) %s", + channel->local_channel, +@@ -228,6 +236,10 @@ SSH_PACKET_CALLBACK(ssh_packet_channel_open_fail){ + SAFE_FREE(error); + channel->state=SSH_CHANNEL_STATE_OPEN_DENIED; + return SSH_PACKET_USED; ++ ++error: ++ ssh_set_error(session, SSH_FATAL, "Invalid packet"); ++ return SSH_PACKET_USED; + } + + static int ssh_channel_open_termination(void *c){ +-- +cgit v1.2.1 + diff --git a/libssh-stable-0p8-CVE-2018-10933-part7.patch b/libssh-stable-0p8-CVE-2018-10933-part7.patch new file mode 100644 index 0000000..9b51747 --- /dev/null +++ b/libssh-stable-0p8-CVE-2018-10933-part7.patch @@ -0,0 +1,871 @@ +From 203818608ac8a83d68098f008306c3a568ac4cac Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Tue, 28 Aug 2018 18:13:03 +0200 +Subject: CVE-2018-10933: Introduced packet filtering + +The packet filter checks required states for the incoming packets and +reject them if they arrived in the wrong state. + +Fixes T101 + +Signed-off-by: Anderson Toshiyuki Sasaki +Reviewed-by: Andreas Schneider +--- + include/libssh/packet.h | 6 + + src/packet.c | 809 +++++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 813 insertions(+), 2 deletions(-) + +diff --git a/include/libssh/packet.h b/include/libssh/packet.h +index a3bcb9a8..fbe09700 100644 +--- a/include/libssh/packet.h ++++ b/include/libssh/packet.h +@@ -43,6 +43,12 @@ enum ssh_packet_state_e { + PACKET_STATE_PROCESSING + }; + ++enum ssh_packet_filter_result_e { ++ SSH_PACKET_UNKNOWN, ++ SSH_PACKET_ALLOWED, ++ SSH_PACKET_DENIED ++}; ++ + int ssh_packet_send(ssh_session session); + + SSH_PACKET_CALLBACK(ssh_packet_unimplemented); +diff --git a/src/packet.c b/src/packet.c +index aa2f17f0..0b070fd4 100644 +--- a/src/packet.c ++++ b/src/packet.c +@@ -128,6 +128,797 @@ static ssh_packet_callback default_packet_handlers[]= { + ssh_packet_channel_failure, // SSH2_MSG_CHANNEL_FAILURE 100 + }; + ++/** @internal ++ * @brief check if the received packet is allowed for the current session state ++ * @param session current ssh_session ++ * @returns SSH_PACKET_ALLOWED if the packet is allowed; SSH_PACKET_DENIED ++ * if the packet arrived in wrong state; SSH_PACKET_UNKNOWN if the packet type ++ * is unknown ++ */ ++static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session session) ++{ ++ enum ssh_packet_filter_result_e rc; ++ ++#ifdef DEBUG_PACKET ++ SSH_LOG(SSH_LOG_PACKET, "Filtering packet type %d", ++ session->in_packet.type); ++#endif ++ ++ switch(session->in_packet.type) { ++ case SSH2_MSG_DISCONNECT: // 1 ++ /* ++ * States required: ++ * - None ++ * ++ * Transitions: ++ * - session->socket->state = SSH_SOCKET_CLOSED ++ * - session->session_state = SSH_SESSION_STATE_ERROR ++ * */ ++ ++ /* Always allowed */ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_IGNORE: // 2 ++ /* ++ * States required: ++ * - None ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ /* Always allowed */ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_UNIMPLEMENTED: // 3 ++ /* ++ * States required: ++ * - None ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ /* Always allowed */ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_DEBUG: // 4 ++ /* ++ * States required: ++ * - None ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ /* Always allowed */ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_SERVICE_REQUEST: // 5 ++ /* Server only */ ++ ++ /* ++ * States required: ++ * - session->session_state == SSH_SESSION_STATE_AUTHENTICATING ++ * or session->session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * - session->dh_handshake_state == DH_STATE_FINISHED ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ /* If this is a client, reject the message */ ++ if (session->client) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) && ++ (session->session_state != SSH_SESSION_STATE_AUTHENTICATED)) ++ { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->dh_handshake_state != DH_STATE_FINISHED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_SERVICE_ACCEPT: // 6 ++ /* ++ * States required: ++ * - session->session_state == SSH_SESSION_STATE_AUTHENTICATING ++ * or session->session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * - session->dh_handshake_state == DH_STATE_FINISHED ++ * - session->auth.service_state == SSH_AUTH_SERVICE_SENT ++ * ++ * Transitions: ++ * - auth.service_state = SSH_AUTH_SERVICE_ACCEPTED ++ * */ ++ ++ if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) && ++ (session->session_state != SSH_SESSION_STATE_AUTHENTICATED)) ++ { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->dh_handshake_state != DH_STATE_FINISHED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ /* TODO check if only auth service can be requested */ ++ if (session->auth.service_state != SSH_AUTH_SERVICE_SENT) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_EXT_INFO: // 7 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATING ++ * - dh_handshake_state == DH_STATE_FINISHED ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->dh_handshake_state != DH_STATE_FINISHED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_KEXINIT: // 20 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * or session_state == SSH_SESSION_STATE_INITIAL_KEX ++ * - dh_handshake_state == DH_STATE_INIT ++ * or dh_handshake_state == DH_STATE_FINISHED (re-exchange) ++ * ++ * Transitions: ++ * - session->dh_handshake_state = DH_STATE_INIT ++ * - session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED ++ * ++ * On server: ++ * - session->session_state = SSH_SESSION_STATE_DH ++ * */ ++ ++ if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATED) && ++ (session->session_state != SSH_SESSION_STATE_INITIAL_KEX)) ++ { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if ((session->dh_handshake_state != DH_STATE_INIT) && ++ (session->dh_handshake_state != DH_STATE_FINISHED)) ++ { ++ rc = SSH_PACKET_DENIED; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_NEWKEYS: // 21 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_DH ++ * - dh_handshake_state == DH_STATE_NEWKEYS_SENT ++ * ++ * Transitions: ++ * - session->dh_handshake_state = DH_STATE_FINISHED ++ * - session->session_state = SSH_SESSION_STATE_AUTHENTICATING ++ * if session->flags & SSH_SESSION_FLAG_AUTHENTICATED ++ * - session->session_state = SSH_SESSION_STATE_AUTHENTICATED ++ * */ ++ ++ /* If DH has not been started, reject message */ ++ if (session->session_state != SSH_SESSION_STATE_DH) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ /* Only allowed if dh_handshake_state is in NEWKEYS_SENT state */ ++ if (session->dh_handshake_state != DH_STATE_NEWKEYS_SENT) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_KEXDH_INIT: // 30 ++ // SSH2_MSG_KEX_ECDH_INIT: // 30 ++ // SSH2_MSG_ECMQV_INIT: // 30 ++ // SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: // 30 ++ ++ /* Server only */ ++ ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_DH ++ * - dh_handshake_state == DH_STATE_INIT ++ * ++ * Transitions: ++ * - session->dh_handshake_state = DH_STATE_INIT_SENT ++ * then calls dh_handshake_server which triggers: ++ * - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_DH) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ /* Only allowed if dh_handshake_state is in initial state */ ++ if (session->dh_handshake_state != DH_STATE_INIT) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_KEXDH_REPLY: // 31 ++ // SSH2_MSG_KEX_ECDH_REPLY: // 31 ++ // SSH2_MSG_ECMQV_REPLY: // 31 ++ // SSH2_MSG_KEX_DH_GEX_GROUP: // 31 ++ ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_DH ++ * - dh_handshake_state == DH_STATE_INIT_SENT ++ * ++ * Transitions: ++ * - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_DH) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->dh_handshake_state != DH_STATE_INIT_SENT) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_KEX_DH_GEX_INIT: // 32 ++ /* TODO Not filtered */ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_KEX_DH_GEX_REPLY: // 33 ++ /* TODO Not filtered */ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_KEX_DH_GEX_REQUEST: // 34 ++ /* TODO Not filtered */ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_USERAUTH_REQUEST: // 50 ++ /* Server only */ ++ ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATING ++ * - dh_hanshake_state == DH_STATE_FINISHED ++ * ++ * Transitions: ++ * - if authentication was successful: ++ * - session_state = SSH_SESSION_STATE_AUTHENTICATED ++ * */ ++ ++ /* If this is a client, reject the message */ ++ if (session->client) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->dh_handshake_state != DH_STATE_FINISHED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_USERAUTH_FAILURE: // 51 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATING ++ * - dh_hanshake_state == DH_STATE_FINISHED ++ * - session->auth.state == SSH_AUTH_STATE_KBDINT_SENT ++ * or session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT ++ * or session->auth.state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT ++ * or session->auth.state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT ++ * or session->auth.state == SSH_AUTH_STATE_GSSAPI_MIC_SENT ++ * ++ * Transitions: ++ * - if unpacking failed: ++ * - session->auth.state = SSH_AUTH_ERROR ++ * - if failure was partial: ++ * - session->auth.state = SSH_AUTH_PARTIAL ++ * - else: ++ * - session->auth.state = SSH_AUTH_STATE_FAILED ++ * */ ++ ++ /* If this is a server, reject the message */ ++ if (session->server) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->dh_handshake_state != DH_STATE_FINISHED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_USERAUTH_SUCCESS: // 52 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATING ++ * - dh_hanshake_state == DH_STATE_FINISHED ++ * - session->auth.state == SSH_AUTH_STATE_KBDINT_SENT ++ * or session->auth.state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT ++ * or session->auth.state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT ++ * or session->auth.state == SSH_AUTH_STATE_GSSAPI_MIC_SENT ++ * or session->auth.state == SSH_AUTH_STATE_AUTH_NONE_SENT ++ * ++ * Transitions: ++ * - session->auth.state = SSH_AUTH_STATE_SUCCESS ++ * - session->session_state = SSH_SESSION_STATE_AUTHENTICATED ++ * - session->flags |= SSH_SESSION_FLAG_AUTHENTICATED ++ * - sessions->auth.current_method = SSH_AUTH_METHOD_UNKNOWN ++ * */ ++ ++ /* If this is a server, reject the message */ ++ if (session->server) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->dh_handshake_state != DH_STATE_FINISHED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if ((session->auth.state != SSH_AUTH_STATE_KBDINT_SENT) && ++ (session->auth.state != SSH_AUTH_STATE_PUBKEY_AUTH_SENT) && ++ (session->auth.state != SSH_AUTH_STATE_PASSWORD_AUTH_SENT) && ++ (session->auth.state != SSH_AUTH_STATE_GSSAPI_MIC_SENT) && ++ (session->auth.state != SSH_AUTH_STATE_AUTH_NONE_SENT)) ++ { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_USERAUTH_BANNER: // 53 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATING ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_USERAUTH_PK_OK: // 60 ++ // SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // 60 ++ // SSH2_MSG_USERAUTH_INFO_REQUEST: // 60 ++ // SSH2_MSG_USERAUTH_GSSAPI_RESPONSE: // 60 ++ ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATING ++ * - session->auth.state == SSH_AUTH_STATE_KBDINT_SENT ++ * or ++ * session->auth.state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT ++ * or ++ * session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT ++ * ++ * Transitions: ++ * Depending on the current state, the message is treated ++ * differently: ++ * - session->auth.state == SSH_AUTH_STATE_KBDINT_SENT ++ * - session->auth.state = SSH_AUTH_STATE_INFO ++ * - session->auth.state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT ++ * - session->auth.state = SSH_AUTH_STATE_GSSAPI_TOKEN ++ * - session->auth.state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT ++ * - session->auth.state = SSH_AUTH_STATE_PK_OK ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if ((session->auth.state != SSH_AUTH_STATE_KBDINT_SENT) && ++ (session->auth.state != SSH_AUTH_STATE_PUBKEY_OFFER_SENT) && ++ (session->auth.state != SSH_AUTH_STATE_GSSAPI_REQUEST_SENT)) ++ { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_USERAUTH_INFO_RESPONSE: // 61 ++ // SSH2_MSG_USERAUTH_GSSAPI_TOKEN: // 61 ++ ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATING ++ * - session_state->auth.state == SSH_SESSION_STATE_GSSAPI_TOKEN ++ * or ++ * session_state->auth.state == SSH_SESSION_STATE_INFO ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if ((session->auth.state != SSH_AUTH_STATE_INFO) && ++ (session->auth.state != SSH_AUTH_STATE_GSSAPI_TOKEN)) ++ { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE: // 63 ++ /* TODO Not filtered */ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_USERAUTH_GSSAPI_ERROR: // 64 ++ /* TODO Not filtered */ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_USERAUTH_GSSAPI_ERRTOK: // 65 ++ /* TODO Not filtered */ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_USERAUTH_GSSAPI_MIC: // 66 ++ /* Server only */ ++ ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATING ++ * - session->gssapi->state == SSH_GSSAPI_STATE_RCV_MIC ++ * ++ * Transitions: ++ * Depending on the result of the verification, the states are ++ * changed: ++ * - SSH_AUTH_SUCCESS: ++ * - session->session_state = SSH_SESSION_STATE_AUTHENTICATED ++ * - session->flags != SSH_SESSION_FLAG_AUTHENTICATED ++ * - SSH_AUTH_PARTIAL: ++ * - None ++ * - any other case: ++ * - None ++ * */ ++ ++ /* If this is a client, reject the message */ ++ if (session->client) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->dh_handshake_state != DH_STATE_FINISHED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_GLOBAL_REQUEST: // 80 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_REQUEST_SUCCESS: // 81 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING ++ * ++ * Transitions: ++ * - session->global_req_state == SSH_CHANNEL_REQ_STATE_ACCEPTED ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_REQUEST_FAILURE: // 82 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING ++ * ++ * Transitions: ++ * - session->global_req_state == SSH_CHANNEL_REQ_STATE_DENIED ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_OPEN: // 90 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: // 91 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * ++ * Transitions: ++ * - channel->state = SSH_CHANNEL_STATE_OPEN ++ * - channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_OPEN_FAILURE: // 92 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * ++ * Transitions: ++ * - channel->state = SSH_CHANNEL_STATE_OPEN_DENIED ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_WINDOW_ADJUST: // 93 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_DATA: // 94 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_EXTENDED_DATA: // 95 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_EOF: // 96 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * ++ * Transitions: ++ * - None ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_CLOSE: // 97 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * ++ * Transitions: ++ * - channel->state = SSH_CHANNEL_STATE_CLOSED ++ * - channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_REQUEST: // 98 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * ++ * Transitions: ++ * - Depends on the request ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_SUCCESS: // 99 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING ++ * ++ * Transitions: ++ * - channel->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ case SSH2_MSG_CHANNEL_FAILURE: // 100 ++ /* ++ * States required: ++ * - session_state == SSH_SESSION_STATE_AUTHENTICATED ++ * - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING ++ * ++ * Transitions: ++ * - channel->request_state = SSH_CHANNEL_REQ_STATE_DENIED ++ * */ ++ ++ if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { ++ rc = SSH_PACKET_DENIED; ++ break; ++ } ++ ++ rc = SSH_PACKET_ALLOWED; ++ break; ++ default: ++ /* Unknown message, do not filter */ ++ rc = SSH_PACKET_UNKNOWN; ++ goto end; ++ } ++ ++end: ++#ifdef DEBUG_PACKET ++ if (rc == SSH_PACKET_DENIED) { ++ SSH_LOG(SSH_LOG_PACKET, "REJECTED packet type %d: ", ++ session->in_packet.type); ++ } ++ ++ if (rc == SSH_PACKET_UNKNOWN) { ++ SSH_LOG(SSH_LOG_PACKET, "UNKNOWN packet type %d", ++ session->in_packet.type); ++ } ++#endif ++ ++ return rc; ++} ++ + /* in nonblocking mode, socket_read will read as much as it can, and return */ + /* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */ + /* in blocking mode, it will read at least len bytes and will block until it's ok. */ +@@ -158,6 +949,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) + uint32_t packet_len, compsize, payloadsize; + uint8_t padding; + size_t processed = 0; /* number of byte processed from the callback */ ++ enum ssh_packet_filter_result_e filter_result; + + if(session->current_crypto != NULL) { + current_macsize = hmac_digest_len(session->current_crypto->in_hmac); +@@ -345,8 +1137,21 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) + "packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]", + session->in_packet.type, packet_len, padding, compsize, payloadsize); + +- /* Execute callbacks */ +- ssh_packet_process(session, session->in_packet.type); ++ /* Check if the packet is expected */ ++ filter_result = ssh_packet_incoming_filter(session); ++ ++ switch(filter_result) { ++ case SSH_PACKET_ALLOWED: ++ /* Execute callbacks */ ++ ssh_packet_process(session, session->in_packet.type); ++ break; ++ case SSH_PACKET_DENIED: ++ goto error; ++ case SSH_PACKET_UNKNOWN: ++ ssh_packet_send_unimplemented(session, session->recv_seq - 1); ++ break; ++ } ++ + session->packet_state = PACKET_STATE_INIT; + if (processed < receivedlen) { + /* Handle a potential packet left in socket buffer */ +-- +cgit v1.2.1 + diff --git a/libssh-stable-0p8-CVE-2018-10933-part8.patch b/libssh-stable-0p8-CVE-2018-10933-part8.patch new file mode 100644 index 0000000..8ef331c --- /dev/null +++ b/libssh-stable-0p8-CVE-2018-10933-part8.patch @@ -0,0 +1,543 @@ +From 09a7638575b3c07ad227763e1f03f7553b045e79 Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Fri, 7 Sep 2018 15:26:49 +0200 +Subject: CVE-2018-10933: Add tests for packet filtering + +Created the test torture_packet_filter.c which tests if packets are +being correctly filtered. + +Fixes T101 + +Signed-off-by: Anderson Toshiyuki Sasaki +Reviewed-by: Andreas Schneider +--- + tests/unittests/CMakeLists.txt | 3 + + tests/unittests/torture_packet_filter.c | 502 ++++++++++++++++++++++++++++++++ + 2 files changed, 505 insertions(+) + create mode 100644 tests/unittests/torture_packet_filter.c + +diff --git a/tests/unittests/CMakeLists.txt b/tests/unittests/CMakeLists.txt +index 397ebd05..13887ff1 100644 +--- a/tests/unittests/CMakeLists.txt ++++ b/tests/unittests/CMakeLists.txt +@@ -35,6 +35,9 @@ target_compile_options(torture_knownhosts_parsing PRIVATE ${DEFAULT_C_COMPILE_FL + add_cmocka_test(torture_hashes torture_hashes.c ${TEST_TARGET_LIBRARIES}) + target_compile_options(torture_hashes PRIVATE ${DEFAULT_C_COMPILE_FLAGS}) + ++add_cmocka_test(torture_packet_filter torture_packet_filter.c ${TORTURE_LIBRARY}) ++target_compile_options(torture_packet_filter PRIVATE ${DEFAULT_C_COMPILE_FLAGS}) ++ + if (CMAKE_USE_PTHREADS_INIT) + add_cmocka_test(torture_rand torture_rand.c ${TEST_TARGET_LIBRARIES}) + target_compile_options(torture_rand PRIVATE ${DEFAULT_C_COMPILE_FLAGS}) +diff --git a/tests/unittests/torture_packet_filter.c b/tests/unittests/torture_packet_filter.c +new file mode 100644 +index 00000000..72cbc4cd +--- /dev/null ++++ b/tests/unittests/torture_packet_filter.c +@@ -0,0 +1,502 @@ ++/* ++ * This file is part of the SSH Library ++ * ++ * Copyright (c) 2018 by Anderson Toshiyuki Sasaki ++ * ++ * The SSH Library is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU Lesser General Public License as published by ++ * the Free Software Foundation; either version 2.1 of the License, or (at your ++ * option) any later version. ++ * ++ * The SSH Library is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ++ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public ++ * License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with the SSH Library; see the file COPYING. If not, write to ++ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, ++ * MA 02111-1307, USA. ++ */ ++ ++/* ++ * This test checks if the messages accepted by the packet filter were intented ++ * to be accepted. ++ * ++ * The process consists in 2 steps: ++ * - Try the filter with a message type in an arbitrary state ++ * - If the message is accepted by the filter, check if the message is in the ++ * set of accepted states. ++ * ++ * Only the values selected by the flag (COMPARE_*) are considered. ++ * */ ++ ++#include "config.h" ++ ++#define LIBSSH_STATIC ++ ++#include "torture.h" ++#include "libssh/priv.h" ++#include "libssh/libssh.h" ++#include "libssh/session.h" ++#include "libssh/auth.h" ++#include "libssh/ssh2.h" ++#include "libssh/packet.h" ++ ++#include "packet.c" ++ ++#define COMPARE_SESSION_STATE 1 ++#define COMPARE_ROLE (1 << 1) ++#define COMPARE_DH_STATE (1 << 2) ++#define COMPARE_AUTH_STATE (1 << 3) ++#define COMPARE_GLOBAL_REQ_STATE (1 << 4) ++#define COMPARE_CURRENT_METHOD (1 << 5) ++ ++#define SESSION_STATE_COUNT 11 ++#define DH_STATE_COUNT 4 ++#define AUTH_STATE_COUNT 15 ++#define GLOBAL_REQ_STATE_COUNT 5 ++#define MESSAGE_COUNT 100 // from 1 to 100 ++ ++#define ROLE_CLIENT 0 ++#define ROLE_SERVER 1 ++ ++/* ++ * This is the list of currently unfiltered message types. ++ * Only unrecognized types should be in this list. ++ * */ ++static uint8_t unfiltered[] = { ++ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ++ 22, 23, 24, 25, 26, 27, 28, 29, ++ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, ++ 54, 55, 56, 57, 58, 59, ++ 62, ++ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, ++ 83, 84, 85, 86, 87, 88, 89, ++}; ++ ++typedef struct global_state_st { ++ /* If the bit in this flag is zero, the corresponding state is not ++ * considered, working as a wildcard (meaning any value is accepted) */ ++ uint32_t flags; ++ uint8_t role; ++ enum ssh_session_state_e session; ++ enum ssh_dh_state_e dh; ++ enum ssh_auth_state_e auth; ++ enum ssh_channel_request_state_e global_req; ++} global_state; ++ ++static int cmp_state(const void *e1, const void *e2) ++{ ++ global_state *s1 = (global_state *) e1; ++ global_state *s2 = (global_state *) e2; ++ ++ /* Compare role (client == 0 or server == 1)*/ ++ if (s1->role < s2->role) { ++ return -1; ++ } ++ else if (s1->role > s2->role) { ++ return 1; ++ } ++ ++ /* Compare session state */ ++ if (s1->session < s2->session) { ++ return -1; ++ } ++ else if (s1->session > s2->session) { ++ return 1; ++ } ++ ++ /* Compare DH state */ ++ if (s1->dh < s2->dh) { ++ return -1; ++ } ++ else if (s1->dh > s2->dh) { ++ return 1; ++ } ++ ++ /* Compare auth */ ++ if (s1->auth < s2->auth) { ++ return -1; ++ } ++ else if (s1->auth > s2->auth) { ++ return 1; ++ } ++ ++ /* Compare global_req */ ++ if (s1->global_req < s2->global_req) { ++ return -1; ++ } ++ else if (s1->global_req > s2->global_req) { ++ return 1; ++ } ++ ++ /* If all equal, they are equal */ ++ return 0; ++} ++ ++static int cmp_state_search(const void *key, const void *array_element) ++{ ++ global_state *s1 = (global_state *) key; ++ global_state *s2 = (global_state *) array_element; ++ ++ int result = 0; ++ ++ if (s2->flags & COMPARE_ROLE) { ++ /* Compare role (client == 0 or server == 1)*/ ++ if (s1->role < s2->role) { ++ return -1; ++ } ++ else if (s1->role > s2->role) { ++ return 1; ++ } ++ } ++ ++ if (s2->flags & COMPARE_SESSION_STATE) { ++ /* Compare session state */ ++ if (s1->session < s2->session) { ++ result = -1; ++ goto end; ++ } ++ else if (s1->session > s2->session) { ++ result = 1; ++ goto end; ++ } ++ } ++ ++ if (s2->flags & COMPARE_DH_STATE) { ++ /* Compare DH state */ ++ if (s1->dh < s2->dh) { ++ result = -1; ++ goto end; ++ } ++ else if (s1->dh > s2->dh) { ++ result = 1; ++ goto end; ++ } ++ } ++ ++ if (s2->flags & COMPARE_AUTH_STATE) { ++ /* Compare auth */ ++ if (s1->auth < s2->auth) { ++ result = -1; ++ goto end; ++ } ++ else if (s1->auth > s2->auth) { ++ result = 1; ++ goto end; ++ } ++ } ++ ++ if (s2->flags & COMPARE_GLOBAL_REQ_STATE) { ++ /* Compare global_req */ ++ if (s1->global_req < s2->global_req) { ++ result = -1; ++ goto end; ++ } ++ else if (s1->global_req > s2->global_req) { ++ result = 1; ++ goto end; ++ } ++ } ++ ++end: ++ return result; ++} ++ ++static int is_state_accepted(global_state *tested, global_state *accepted, ++ int accepted_len) ++{ ++ global_state *found = NULL; ++ ++ found = bsearch(tested, accepted, accepted_len, sizeof(global_state), ++ cmp_state_search); ++ ++ if (found != NULL) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int cmp_uint8(const void *i, const void *j) ++{ ++ uint8_t e1 = *((uint8_t *)i); ++ uint8_t e2 = *((uint8_t *)j); ++ ++ if (e1 < e2) { ++ return -1; ++ } ++ else if (e1 > e2) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int check_unfiltered(uint8_t msg_type) ++{ ++ uint8_t *found; ++ ++ found = bsearch(&msg_type, unfiltered, sizeof(unfiltered)/sizeof(uint8_t), ++ sizeof(uint8_t), cmp_uint8); ++ ++ if (found != NULL) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static void torture_packet_filter_check_unfiltered(void **state) ++{ ++ ssh_session session; ++ ++ int role_c; ++ int auth_c; ++ int session_c; ++ int dh_c; ++ int global_req_c; ++ ++ uint8_t msg_type; ++ ++ enum ssh_packet_filter_result_e rc; ++ int in_unfiltered; ++ ++ session = ssh_new(); ++ ++ for (msg_type = 1; msg_type <= MESSAGE_COUNT; msg_type++) { ++ session->in_packet.type = msg_type; ++ for (role_c = 0; role_c < 2; role_c++) { ++ session->server = role_c; ++ for (session_c = 0; session_c < SESSION_STATE_COUNT; session_c++) { ++ session->session_state = session_c; ++ for (dh_c = 0; dh_c < DH_STATE_COUNT; dh_c++) { ++ session->dh_handshake_state = dh_c; ++ for (auth_c = 0; auth_c < AUTH_STATE_COUNT; auth_c++) { ++ session->auth.state = auth_c; ++ for (global_req_c = 0; ++ global_req_c < GLOBAL_REQ_STATE_COUNT; ++ global_req_c++) ++ { ++ session->global_req_state = global_req_c; ++ ++ rc = ssh_packet_incoming_filter(session); ++ ++ if (rc == SSH_PACKET_UNKNOWN) { ++ in_unfiltered = check_unfiltered(msg_type); ++ ++ if (!in_unfiltered) { ++ fprintf(stderr, "Message type %d UNFILTERED " ++ "in state: role %d, session %d, dh %d, auth %d\n", ++ msg_type, role_c, session_c, dh_c, auth_c); ++ } ++ assert_int_equal(in_unfiltered, 1); ++ } ++ else { ++ in_unfiltered = check_unfiltered(msg_type); ++ ++ if (in_unfiltered) { ++ fprintf(stderr, "Message type %d NOT UNFILTERED " ++ "in state: role %d, session %d, dh %d, auth %d\n", ++ msg_type, role_c, session_c, dh_c, auth_c); ++ } ++ assert_int_equal(in_unfiltered, 0); ++ } ++ } ++ } ++ } ++ } ++ } ++ } ++ ssh_free(session); ++} ++ ++static int check_message_in_all_states(global_state accepted[], ++ int accepted_count, uint8_t msg_type) ++{ ++ ssh_session session; ++ ++ int role_c; ++ int auth_c; ++ int session_c; ++ int dh_c; ++ int global_req_c; ++ ++ enum ssh_packet_filter_result_e rc; ++ int in_accepted; ++ ++ global_state key; ++ ++ session = ssh_new(); ++ ++ /* Sort the accepted array so that the elements can be searched using ++ * bsearch */ ++ qsort(accepted, accepted_count, sizeof(global_state), cmp_state); ++ ++ session->in_packet.type = msg_type; ++ ++ for (role_c = 0; role_c < 2; role_c++) { ++ session->server = role_c; ++ key.role = role_c; ++ for (session_c = 0; session_c < SESSION_STATE_COUNT; session_c++) { ++ session->session_state = session_c; ++ key.session = session_c; ++ for (dh_c = 0; dh_c < DH_STATE_COUNT; dh_c++) { ++ session->dh_handshake_state = dh_c; ++ key.dh = dh_c; ++ for (auth_c = 0; auth_c < AUTH_STATE_COUNT; auth_c++) { ++ session->auth.state = auth_c; ++ key.auth = auth_c; ++ for (global_req_c = 0; ++ global_req_c < GLOBAL_REQ_STATE_COUNT; ++ global_req_c++) ++ { ++ session->global_req_state = global_req_c; ++ key.global_req = global_req_c; ++ ++ rc = ssh_packet_incoming_filter(session); ++ ++ if (rc == SSH_PACKET_ALLOWED) { ++ in_accepted = is_state_accepted(&key, accepted, ++ accepted_count); ++ ++ if (!in_accepted) { ++ fprintf(stderr, "Message type %d ALLOWED " ++ "in state: role %d, session %d, dh %d, auth %d\n", ++ msg_type, role_c, session_c, dh_c, auth_c); ++ } ++ assert_int_equal(in_accepted, 1); ++ } ++ else if (rc == SSH_PACKET_DENIED) { ++ in_accepted = is_state_accepted(&key, accepted, accepted_count); ++ ++ if (in_accepted) { ++ fprintf(stderr, "Message type %d DENIED " ++ "in state: role %d, session %d, dh %d, auth %d\n", ++ msg_type, role_c, session_c, dh_c, auth_c); ++ } ++ assert_int_equal(in_accepted, 0); ++ } ++ else { ++ fprintf(stderr, "Message type %d UNFILTERED " ++ "in state: role %d, session %d, dh %d, auth %d\n", ++ msg_type, role_c, session_c, dh_c, auth_c); ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ ssh_free(session); ++ return 0; ++} ++ ++static void torture_packet_filter_check_auth_success(void **state) ++{ ++ int rc; ++ ++ global_state accepted[] = { ++ { ++ .flags = (COMPARE_SESSION_STATE | ++ COMPARE_ROLE | ++ COMPARE_AUTH_STATE | ++ COMPARE_DH_STATE), ++ .role = ROLE_CLIENT, ++ .session = SSH_SESSION_STATE_AUTHENTICATING, ++ .dh = DH_STATE_FINISHED, ++ .auth = SSH_AUTH_STATE_PUBKEY_AUTH_SENT, ++ }, ++ { ++ .flags = (COMPARE_SESSION_STATE | ++ COMPARE_ROLE | ++ COMPARE_AUTH_STATE | ++ COMPARE_DH_STATE), ++ .role = ROLE_CLIENT, ++ .session = SSH_SESSION_STATE_AUTHENTICATING, ++ .dh = DH_STATE_FINISHED, ++ .auth = SSH_AUTH_STATE_PASSWORD_AUTH_SENT, ++ }, ++ { ++ .flags = (COMPARE_SESSION_STATE | ++ COMPARE_ROLE | ++ COMPARE_AUTH_STATE | ++ COMPARE_DH_STATE), ++ .role = ROLE_CLIENT, ++ .session = SSH_SESSION_STATE_AUTHENTICATING, ++ .dh = DH_STATE_FINISHED, ++ .auth = SSH_AUTH_STATE_GSSAPI_MIC_SENT, ++ }, ++ { ++ .flags = (COMPARE_SESSION_STATE | ++ COMPARE_ROLE | ++ COMPARE_AUTH_STATE | ++ COMPARE_DH_STATE), ++ .role = ROLE_CLIENT, ++ .session = SSH_SESSION_STATE_AUTHENTICATING, ++ .dh = DH_STATE_FINISHED, ++ .auth = SSH_AUTH_STATE_KBDINT_SENT, ++ }, ++ { ++ .flags = (COMPARE_SESSION_STATE | ++ COMPARE_ROLE | ++ COMPARE_AUTH_STATE | ++ COMPARE_DH_STATE | ++ COMPARE_CURRENT_METHOD), ++ .role = ROLE_CLIENT, ++ .session = SSH_SESSION_STATE_AUTHENTICATING, ++ .dh = DH_STATE_FINISHED, ++ .auth = SSH_AUTH_STATE_AUTH_NONE_SENT, ++ } ++ }; ++ ++ int accepted_count = 5; ++ ++ /* Unused */ ++ (void) state; ++ ++ rc = check_message_in_all_states(accepted, accepted_count, ++ SSH2_MSG_USERAUTH_SUCCESS); ++ ++ assert_int_equal(rc, 0); ++} ++ ++static void torture_packet_filter_check_channel_open(void **state) ++{ ++ int rc; ++ ++ /* The only condition to accept a CHANNEL_OPEN is to be authenticated */ ++ global_state accepted[] = { ++ { ++ .flags = COMPARE_SESSION_STATE, ++ .session = SSH_SESSION_STATE_AUTHENTICATED, ++ } ++ }; ++ ++ int accepted_count = 1; ++ ++ /* Unused */ ++ (void) state; ++ ++ rc = check_message_in_all_states(accepted, accepted_count, ++ SSH2_MSG_CHANNEL_OPEN); ++ ++ assert_int_equal(rc, 0); ++} ++ ++int torture_run_tests(void) ++{ ++ int rc; ++ struct CMUnitTest tests[] = { ++ cmocka_unit_test(torture_packet_filter_check_auth_success), ++ cmocka_unit_test(torture_packet_filter_check_channel_open), ++ cmocka_unit_test(torture_packet_filter_check_unfiltered), ++ }; ++ ++ ssh_init(); ++ torture_filter_tests(tests); ++ rc = cmocka_run_group_tests(tests, NULL, NULL); ++ ssh_finalize(); ++ return rc; ++} +-- +cgit v1.2.1 + diff --git a/libssh.keyring b/libssh.keyring new file mode 100644 index 0000000..411bf36 Binary files /dev/null and b/libssh.keyring differ diff --git a/libssh.spec b/libssh.spec new file mode 100644 index 0000000..105e559 --- /dev/null +++ b/libssh.spec @@ -0,0 +1,104 @@ +Name: libssh +Version: 0.8.3 +Release: 4 +Summary: A library implementing the SSH protocol +License: LGPLv2+ +URL: https://www.libssh.org +Source0: https://www.libssh.org/files/0.8/%{name}-%{version}.tar.xz +Source1: https://www.libssh.org/files/0.8/%{name}-%{version}.tar.xz.asc +Source2: https://cryptomilk.org/gpgkey-8DFF53E18F2ABC8D8F3C92237EE0FC4DCC014E3D.gpg#/%{name}.keyring + +Patch1: libssh-0.8.3-fix-covscan-errors.patch +#patches6000-patches6007 come from https://git.libssh.org/ +Patch6000: libssh-stable-0p8-CVE-2018-10933-part1.patch +Patch6001: libssh-stable-0p8-CVE-2018-10933-part2.patch +Patch6002: libssh-stable-0p8-CVE-2018-10933-part3.patch +Patch6003: libssh-stable-0p8-CVE-2018-10933-part4.patch +Patch6004: libssh-stable-0p8-CVE-2018-10933-part5.patch +Patch6005: libssh-stable-0p8-CVE-2018-10933-part6.patch +Patch6006: libssh-stable-0p8-CVE-2018-10933-part7.patch +Patch6007: libssh-stable-0p8-CVE-2018-10933-part8.patch + +BuildRequires: cmake libcmocka-devel krb5-devel zlib-devel pkgconfig +BuildRequires: doxygen gcc-c++ gnupg2 openssl-devel + +Provides: libssh_threads.so.4()(64bit) + +%description +The ssh library was designed to be used by programmers needing a working SSH +implementation by the mean of a library. The complete control of the client is +made by the programmer. With libssh, you can remotely execute programs, transfer +files, use a secure and transparent tunnel for your remote programs. With its +Secure FTP implementation, you can play with remote files easily, without +third-party programs others than libcrypto (from openssl). + +%package devel +Summary: Development files for %{name} +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for developing +applications that use %{name}. + +%package_help + +%prep +gpgv2 --quiet --keyring %{SOURCE2} %{SOURCE1} %{SOURCE0} +%autosetup -p1 + +%build +if test ! -e "obj"; then + mkdir obj +fi +pushd obj + +%cmake .. \ + -DUNIT_TESTING=ON + +%make_build VERBOSE=1 +make docs + +popd + +%install +make DESTDIR=%{buildroot} install/fast -C obj + +pushd %{buildroot}%{_libdir} +for i in libssh.so*; +do + _target="${i}" + _link_name="${i%libssh*}libssh_threads${i##*libssh}" + if [ -L "${i}" ]; then + _target="$(readlink ${i})" + fi + ln -s "${_target}" "${_link_name}" +done; +popd + +%ldconfig_scriptlets + +%check +pushd obj +ctest --output-on-failure +popd + +%files +%defattr(-,root,root) +%doc AUTHORS BSD +%license COPYING +%{_libdir}/*.so.4* + +%files devel +%defattr(-,root,root) +%{_includedir}/libssh/ +%{_libdir}/cmake/libssh/ +%{_libdir}/pkgconfig/*.pc +%{_libdir}/*.so + +%files help +%defattr(-,root,root) +%doc README ChangeLog obj/doc/html + +%changelog +* Thu Sep 12 2019 openEuler Buildteam - 0.8.3-4 +- Package init