#include #include "ssh_pubkey_crypto.h" #include "ssh_rsa.h" #include "buffer.h" #include "ssh_endian.h" static RSA *CreateRSAContext(unsigned char *hostkey, int len) { int algo_len, e_len, n_len; RSA *rsa = RSA_new(); BIGNUM *rsa_e = BN_new(); BIGNUM *rsa_n = BN_new(); if (len >= 4) algo_len = be32toh(*(uint32_t *)hostkey); else goto fail; hostkey += 4; len -= 4; if (!(len >= 7 && algo_len == 7 && memcmp(hostkey, "ssh-rsa", 7) == 0)) goto fail; hostkey += 7; len -= 7; if (len >= 4) e_len = be32toh(*(uint32_t *)hostkey); else goto fail; if (len >= 4 + e_len) BN_mpi2bn(hostkey, 4 + e_len, rsa_e); else goto fail; hostkey += 4 + e_len; len -= 4 + e_len; if (len >= 4) n_len = be32toh(*(uint32_t *)hostkey); else goto fail; if (len >= 4 + n_len) BN_mpi2bn(hostkey, 4 + n_len, rsa_n); else goto fail; hostkey += 4 + n_len; len -= 4 + n_len; #ifdef HAVE_OPAQUE_STRUCTS RSA_set0_key(rsa, rsa_n, rsa_e, NULL); #else rsa->n = rsa_n; rsa->e = rsa_e; #endif return rsa; fail: BN_clear_free(rsa_e); BN_clear_free(rsa_n); RSA_free(rsa); return NULL; } static inline const uint8_t *get_str(const uint8_t **data, uint32_t *L) { const uint8_t *ptr = *data; uint32_t len = be32toh(*(uint32_t *)ptr); *data = ptr + 4 + len; *L = len; return ptr + 4; } int verifyRSAKey(ssh_session *ss, const uint8_t *data, size_t len) { const uint8_t *next = data; uint32_t K_S_len; const uint8_t *K_S; K_S = get_str(&next, &K_S_len); ss->K_S_len = K_S_len; ss->K_S = (uint8_t *)malloc(K_S_len); memcpy(ss->K_S, K_S, K_S_len); uint32_t mpint_f_len; const uint8_t *mpint_f; mpint_f = get_str(&next, &mpint_f_len); if (ssh_dh_compute_secret(ss->dh, mpint_f, mpint_f_len) < 0) return -ESECRET; uint32_t s_len; const uint8_t *s; s = get_str(&next, &s_len); buffer vbuf; buffer_init(&vbuf); buffer_append_string(&vbuf, ss->V_C, strlen(ss->V_C)); buffer_append_string(&vbuf, ss->V_S, strlen(ss->V_S)); buffer_append_string(&vbuf, ss->I_C, ss->I_C_len); buffer_append_string(&vbuf, ss->I_S, ss->I_S_len); buffer_append_string(&vbuf, (const char *)K_S, K_S_len); buffer_append(&vbuf, ss->dh->mpint_e, ss->dh->e_len); buffer_append_string(&vbuf, (const char *)mpint_f, mpint_f_len); buffer_append(&vbuf, ss->dh->secret, ss->dh->secret_len); ssh_dh_hash(ss->dh, buffer_data(&vbuf), ss->H, buffer_len(&vbuf)); buffer_deinit(&vbuf); // Start verify // ssh-rsa specifies SHA-1 hashing unsigned char s_H[SHA_DIGEST_LENGTH]; SHA1(ss->H, ss->dh->digest.hashlen, s_H); // Ignore the first 15 bytes of the signature of H sent from server: // algorithm_name_length[4], algorithm_name[7]("ssh-rsa") and signature_length[4]. RSA *rsactx = CreateRSAContext((unsigned char *)K_S, K_S_len); if (rsactx == NULL) return -ERSA; int sig_len = s_len - 15; const uint8_t *sig = s + 15; int res = RSA_verify(NID_sha1, s_H, SHA_DIGEST_LENGTH, sig, sig_len, rsactx); RSA_free(rsactx); return (res == 1); }