/* * Test if the continuously growing buffer size never exceeds 2 time its * real capacity */ static void *thread_growing_buffer(void *threadid) { ssh_buffer buffer = NULL; int i; /* Unused */ (void) threadid; /* Setup */ buffer = ssh_buffer_new(); if (buffer == NULL) { pthread_exit((void *)-1); } ssh_buffer_set_secure(buffer); for (i = 0; i < BUFFER_LIMIT; ++i) { ssh_buffer_add_data(buffer,"A",1); if (buffer->used >= 128) { if (ssh_buffer_get_len(buffer) * 2 < buffer->allocated) { assert_true(ssh_buffer_get_len(buffer) * 2 >= buffer->allocated); } } } /* Teardown */ SSH_BUFFER_FREE(buffer); pthread_exit(NULL); }
static void *thread_ssh_buffer_add_format(void *threadid) { ssh_buffer buffer = NULL; uint8_t b; uint16_t w; uint32_t d; uint64_t q; ssh_string s = NULL; int rc; size_t len; uint8_t verif[] = "\x42\x13\x37\x0b\xad\xc0\xde\x13\x24\x35\x46" "\xac\xbd\xce\xdf" "\x00\x00\x00\x06" "libssh" "\x00\x00\x00\x05" "rocks" "So much" "Fun!"; /* Unused */ (void) threadid; /* Setup */ buffer = ssh_buffer_new(); if (buffer == NULL) { pthread_exit((void *)-1); } ssh_buffer_set_secure(buffer); b = 0x42; w = 0x1337; d = 0xbadc0de; q = 0x13243546acbdcedf; s = ssh_string_from_char("libssh"); rc = ssh_buffer_pack(buffer, "bwdqSsPt", b, w, d, q, s, "rocks", 7, "So much", "Fun!"); assert_int_equal(rc, SSH_OK); len = ssh_buffer_get_len(buffer); assert_int_equal(len, sizeof(verif) - 1); assert_memory_equal(ssh_buffer_get(buffer), verif, sizeof(verif) -1); SSH_STRING_FREE(s); /* Teardown */ SSH_BUFFER_FREE(buffer); pthread_exit(NULL); }
static void *thread_ssh_buffer_get_format_error(void *threadid) { ssh_buffer buffer = NULL; uint8_t b = 0; uint16_t w = 0; uint32_t d = 0; uint64_t q = 0; ssh_string s = NULL; char *s1 = NULL, *s2 = NULL; int rc; uint8_t verif[] = "\x42\x13\x37\x0b\xad\xc0\xde\x13\x24\x35\x46" "\xac\xbd\xce\xdf" "\x00\x00\x00\x06" "libssh" "\x00\x00\x00\x05" "rocks" "So much"; /* Unused */ (void) threadid; /* Setup */ buffer = ssh_buffer_new(); if (buffer == NULL) { pthread_exit((void *)-1); } ssh_buffer_set_secure(buffer); rc = ssh_buffer_add_data(buffer, verif, sizeof(verif) - 1); assert_int_equal(rc, SSH_OK); rc = ssh_buffer_unpack(buffer, "bwdqSsPb", &b, &w, &d, &q, &s, &s1, (size_t)7, &s2, &b); assert_int_equal(rc, SSH_ERROR); assert_null(s); assert_null(s1); assert_null(s2); /* Teardown */ SSH_BUFFER_FREE(buffer); pthread_exit(NULL); }
static void *thread_buffer_pack_badformat(void *threadid) { ssh_buffer buffer = NULL; uint8_t b = 42; int rc; /* Unused */ (void) threadid; /* Setup */ buffer = ssh_buffer_new(); if (buffer == NULL) { pthread_exit((void *)-1); } ssh_buffer_set_secure(buffer); /* first with missing format */ rc = ssh_buffer_pack(buffer, "b", b, b); assert_int_equal(rc, SSH_ERROR); ssh_buffer_reinit(buffer); /* with additional format */ rc = ssh_buffer_pack(buffer, "bb", b); /* check that we detect the missing parameter */ assert_int_equal(rc, SSH_ERROR); /* unpack with missing format */ ssh_buffer_reinit(buffer); rc = ssh_buffer_pack(buffer, "bb", 42, 43); assert_int_equal(rc, SSH_OK); rc = ssh_buffer_unpack(buffer, "b", &b, &b); assert_int_equal(rc, SSH_ERROR); /* not doing the test with additional format as * it could crash the process */ /* Teardown */ SSH_BUFFER_FREE(buffer); pthread_exit(NULL); }
/* * Test the behavior of ssh_buffer_prepend_data */ static void *thread_buffer_prepend(void *threadid) { ssh_buffer buffer = NULL; uint32_t v; /* Unused */ (void) threadid; /* Setup */ buffer = ssh_buffer_new(); if (buffer == NULL) { pthread_exit((void *)-1); } ssh_buffer_set_secure(buffer); ssh_buffer_add_data(buffer, "abcdef", 6); ssh_buffer_prepend_data(buffer, "xyz", 3); assert_int_equal(ssh_buffer_get_len(buffer), 9); assert_memory_equal(ssh_buffer_get(buffer), "xyzabcdef", 9); /* Now remove 4 bytes and see if we can replace them */ ssh_buffer_get_u32(buffer, &v); assert_int_equal(ssh_buffer_get_len(buffer), 5); assert_memory_equal(ssh_buffer_get(buffer), "bcdef", 5); ssh_buffer_prepend_data(buffer, "aris", 4); assert_int_equal(ssh_buffer_get_len(buffer), 9); assert_memory_equal(ssh_buffer_get(buffer), "arisbcdef", 9); /* same thing but we add 5 bytes now */ ssh_buffer_get_u32(buffer, &v); assert_int_equal(ssh_buffer_get_len(buffer), 5); assert_memory_equal(ssh_buffer_get(buffer), "bcdef", 5); ssh_buffer_prepend_data(buffer, "12345", 5); assert_int_equal(ssh_buffer_get_len(buffer), 10); assert_memory_equal(ssh_buffer_get(buffer), "12345bcdef", 10); /* Teardown */ SSH_BUFFER_FREE(buffer); pthread_exit(NULL); }
/* * Test if the continuously growing buffer size never exceeds 2 time its * real capacity, when we remove 1 byte after each call (sliding window) */ static void *thread_growing_buffer_shifting(void *threadid) { ssh_buffer buffer; int i; unsigned char c; /* Unused */ (void) threadid; /* Setup */ buffer = ssh_buffer_new(); if (buffer == NULL) { pthread_exit((void *)-1); } ssh_buffer_set_secure(buffer); for (i = 0; i < 1024; ++i) { ssh_buffer_add_data(buffer,"S",1); } for (i = 0; i < BUFFER_LIMIT; ++i) { ssh_buffer_get_u8(buffer,&c); ssh_buffer_add_data(buffer,"A",1); if (buffer->used >= 128) { if (ssh_buffer_get_len(buffer) * 4 < buffer->allocated) { assert_true(ssh_buffer_get_len(buffer) * 4 >= buffer->allocated); /* Teardown */ SSH_BUFFER_FREE(buffer); pthread_exit(NULL); } } } /* Teardown */ SSH_BUFFER_FREE(buffer); pthread_exit(NULL); }
/* * This function signs the session id as a string then * the content of sigbuf */ ssh_string ssh_pki_do_sign(ssh_session session, ssh_buffer sigbuf, const ssh_key privkey) { struct ssh_crypto_struct *crypto = session->current_crypto ? session->current_crypto : session->next_crypto; ssh_signature sig = NULL; ssh_string sig_blob; ssh_string session_id; int rc; if (privkey == NULL || !ssh_key_is_private(privkey)) { return NULL; } session_id = ssh_string_new(crypto->digest_len); if (session_id == NULL) { return NULL; } ssh_string_fill(session_id, crypto->session_id, crypto->digest_len); if (privkey->type == SSH_KEYTYPE_ECDSA) { #ifdef HAVE_ECC unsigned char ehash[EVP_DIGEST_LEN] = {0}; uint32_t elen; EVPCTX ctx; ctx = evp_init(privkey->ecdsa_nid); if (ctx == NULL) { ssh_string_free(session_id); return NULL; } evp_update(ctx, session_id, ssh_string_len(session_id) + 4); evp_update(ctx, ssh_buffer_get(sigbuf), ssh_buffer_get_len(sigbuf)); evp_final(ctx, ehash, &elen); #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash being signed", ehash, elen); #endif sig = pki_do_sign(privkey, ehash, elen); #endif } else if (privkey->type == SSH_KEYTYPE_ED25519){ ssh_buffer buf; buf = ssh_buffer_new(); if (buf == NULL) { ssh_string_free(session_id); return NULL; } ssh_buffer_set_secure(buf); rc = ssh_buffer_pack(buf, "SP", session_id, ssh_buffer_get_len(sigbuf), ssh_buffer_get(sigbuf)); if (rc != SSH_OK) { ssh_string_free(session_id); ssh_buffer_free(buf); return NULL; } sig = pki_do_sign(privkey, ssh_buffer_get(buf), ssh_buffer_get_len(buf)); ssh_buffer_free(buf); } else { unsigned char hash[SHA_DIGEST_LEN] = {0}; SHACTX ctx; ctx = sha1_init(); if (ctx == NULL) { ssh_string_free(session_id); return NULL; } sha1_update(ctx, session_id, ssh_string_len(session_id) + 4); sha1_update(ctx, ssh_buffer_get(sigbuf), ssh_buffer_get_len(sigbuf)); sha1_final(hash, ctx); #ifdef DEBUG_CRYPTO ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN); #endif sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN); } ssh_string_free(session_id); if (sig == NULL) { return NULL; } rc = ssh_pki_export_signature_blob(sig, &sig_blob); ssh_signature_free(sig); if (rc < 0) { return NULL; } return sig_blob; }
/** @internal * @brief Import a private key in OpenSSH (new) format. This format is * typically used with ed25519 keys but can be used for others. */ ssh_key ssh_pki_openssh_privkey_import(const char *text_key, const char *passphrase, ssh_auth_callback auth_fn, void *auth_data) { const char *ptr=text_key; const char *end; char *base64; int cmp; int rc; int i; ssh_buffer buffer = NULL, privkey_buffer=NULL; char *magic = NULL, *ciphername = NULL, *kdfname = NULL; uint32_t nkeys = 0, checkint1, checkint2; ssh_string kdfoptions = NULL; ssh_string pubkey0 = NULL; ssh_string privkeys = NULL; ssh_string comment = NULL; ssh_key key = NULL; uint8_t padding; cmp = strncmp(ptr, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN)); if (cmp != 0){ SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no header)"); goto error; } ptr += strlen(OPENSSH_HEADER_BEGIN); while(ptr[0] != '\0' && !isspace((int)ptr[0])) { ptr++; } end = strstr(ptr, OPENSSH_HEADER_END); if (end == NULL){ SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no footer)"); goto error; } base64 = malloc(end - ptr + 1); if (base64 == NULL){ goto error; } for (i = 0; ptr < end; ptr++){ if (!isspace((int)ptr[0])) { base64[i] = ptr[0]; i++; } } base64[i] = '\0'; buffer = base64_to_bin(base64); SAFE_FREE(base64); if (buffer == NULL){ SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (base64 error)"); goto error; } rc = ssh_buffer_unpack(buffer, "PssSdSS", strlen(OPENSSH_AUTH_MAGIC) + 1, &magic, &ciphername, &kdfname, &kdfoptions, &nkeys, &pubkey0, &privkeys); if (rc == SSH_ERROR){ SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (unpack error)"); goto error; } cmp = strncmp(magic, OPENSSH_AUTH_MAGIC, strlen(OPENSSH_AUTH_MAGIC)); if (cmp != 0){ SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (bad magic)"); goto error; } ssh_pki_log("Opening OpenSSH private key: ciphername: %s, kdf: %s, nkeys: %d\n", ciphername, kdfname, nkeys); if (nkeys != 1){ SSH_LOG(SSH_LOG_WARN, "Opening OpenSSH private key: only 1 key supported (%d available)", nkeys); goto error; } rc = pki_private_key_decrypt(privkeys, passphrase, ciphername, kdfname, kdfoptions, auth_fn, auth_data); if (rc == SSH_ERROR){ goto error; } privkey_buffer = ssh_buffer_new(); if (privkey_buffer == NULL) { rc = SSH_ERROR; goto error; } ssh_buffer_set_secure(privkey_buffer); ssh_buffer_add_data(privkey_buffer, ssh_string_data(privkeys), ssh_string_len(privkeys)); rc = ssh_buffer_unpack(privkey_buffer, "dd", &checkint1, &checkint2); if (rc == SSH_ERROR || checkint1 != checkint2){ SSH_LOG(SSH_LOG_WARN, "OpenSSH private key unpack error (correct password?)"); goto error; } rc = pki_openssh_import_privkey_blob(privkey_buffer, &key); if (rc == SSH_ERROR){ goto error; } comment = buffer_get_ssh_string(privkey_buffer); SAFE_FREE(comment); /* verify that the remaining data is correct padding */ for (i=1; buffer_get_rest_len(privkey_buffer) > 0; ++i){ buffer_get_u8(privkey_buffer, &padding); if (padding != i){ ssh_key_free(key); key = NULL; ssh_pki_log("Invalid padding"); goto error; } } error: if(buffer != NULL){ ssh_buffer_free(buffer); buffer = NULL; } if(privkey_buffer != NULL){ ssh_buffer_free(privkey_buffer); privkey_buffer = NULL; } SAFE_FREE(magic); SAFE_FREE(ciphername); SAFE_FREE(kdfname); SAFE_FREE(kdfoptions); SAFE_FREE(pubkey0); SAFE_FREE(privkeys); return key; }
static void *thread_ssh_buffer_get_format(void *threadid) { ssh_buffer buffer; uint8_t b = 0; uint16_t w = 0; uint32_t d = 0; uint64_t q = 0; ssh_string s = NULL; char *s1 = NULL, *s2 = NULL; int rc; size_t len; uint8_t verif[] = "\x42\x13\x37\x0b\xad\xc0\xde\x13\x24\x35\x46" "\xac\xbd\xce\xdf" "\x00\x00\x00\x06" "libssh" "\x00\x00\x00\x05" "rocks" "So much"; /* Unused */ (void) threadid; /* Setup */ buffer = ssh_buffer_new(); if (buffer == NULL) { pthread_exit((void *)-1); } ssh_buffer_set_secure(buffer); rc = ssh_buffer_add_data(buffer, verif, sizeof(verif) - 1); assert_int_equal(rc, SSH_OK); rc = ssh_buffer_unpack(buffer, "bwdqSsP", &b, &w, &d, &q, &s, &s1, (size_t)7, &s2); assert_int_equal(rc, SSH_OK); assert_int_equal(b, 0x42); assert_int_equal(w, 0x1337); assert_true(d == 0xbadc0de); assert_true(q == 0x13243546acbdcedf); assert_non_null(s); assert_int_equal(ssh_string_len(s), 6); assert_memory_equal(ssh_string_data(s), "libssh", 6); assert_non_null(s1); assert_string_equal(s1, "rocks"); assert_non_null(s2); assert_memory_equal(s2, "So much", 7); len = ssh_buffer_get_len(buffer); assert_int_equal(len, 0); SAFE_FREE(s); SAFE_FREE(s1); SAFE_FREE(s2); /* Teardown */ SSH_BUFFER_FREE(buffer); pthread_exit(NULL); }