/** * @brief Convert a public key to a base64 encoded key. * * @param[in] key The key to hash * * @param[out] b64_key A pointer to store the allocated base64 encoded key. You * need to free the buffer. * * @return SSH_OK on success, SSH_ERROR on error. * * @see ssh_string_free_char() */ int ssh_pki_export_pubkey_base64(const ssh_key key, char **b64_key) { ssh_string key_blob; unsigned char *b64; if (key == NULL || b64_key == NULL) { return SSH_ERROR; } key_blob = pki_publickey_to_blob(key); if (key_blob == NULL) { return SSH_ERROR; } b64 = bin_to_base64(ssh_string_data(key_blob), ssh_string_len(key_blob)); ssh_string_free(key_blob); if (b64 == NULL) { return SSH_ERROR; } *b64_key = (char *)b64; return SSH_OK; }
/** * @internal * * @brief Create a key_blob from a public key. * * The "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key * Algorithms" for any of the supported protocol 2 key types. * Encoding of EC keys is described in RFC 5656 section 3.1 "Key * Format". * * @param[in] key A public or private key to create the public ssh_string * from. * * @param[out] pblob A pointer to store the newly allocated key blob. You * NEED to free it. * * @return SSH_OK on success, SSH_ERROR otherwise. * * @see ssh_string_free() */ int ssh_pki_export_pubkey_blob(const ssh_key key, ssh_string *pblob) { ssh_string blob; if (key == NULL) { return SSH_OK; } blob = pki_publickey_to_blob(key); if (blob == NULL) { return SSH_ERROR; } *pblob = blob; return SSH_OK; }
ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey, const char *passphrase, ssh_auth_callback auth_fn, void *auth_data) { ssh_buffer buffer; ssh_string str = NULL; ssh_string pubkey_s=NULL; ssh_buffer privkey_buffer = NULL; uint32_t rnd; uint32_t rounds = 16; ssh_string salt=NULL; ssh_string kdf_options=NULL; int to_encrypt=0; unsigned char *b64; uint32_t str_len, len; int rc; if (privkey == NULL) { return NULL; } if (privkey->type != SSH_KEYTYPE_ED25519){ ssh_pki_log("Unsupported key type %s", privkey->type_c); return NULL; } if (passphrase != NULL || auth_fn != NULL){ ssh_pki_log("Enabling encryption for private key export"); to_encrypt = 1; } buffer = ssh_buffer_new(); pubkey_s = pki_publickey_to_blob(privkey); if(buffer == NULL || pubkey_s == NULL){ goto error; } ssh_get_random(&rnd, sizeof(rnd), 0); privkey_buffer = ssh_buffer_new(); if (privkey_buffer == NULL) { goto error; } /* checkint1 & 2 */ rc = ssh_buffer_pack(privkey_buffer, "dd", rnd, rnd); if (rc == SSH_ERROR){ goto error; } rc = pki_openssh_export_privkey_blob(privkey, privkey_buffer); if (rc == SSH_ERROR){ goto error; } /* comment */ rc = ssh_buffer_pack(privkey_buffer, "s", "" /* comment */); if (rc == SSH_ERROR){ goto error; } if (to_encrypt){ ssh_buffer kdf_buf; kdf_buf = ssh_buffer_new(); if (kdf_buf == NULL) { goto error; } salt = ssh_string_new(16); if (salt == NULL){ ssh_buffer_free(kdf_buf); goto error; } ssh_get_random(ssh_string_data(salt),16, 0); ssh_buffer_pack(kdf_buf, "Sd", salt, rounds); kdf_options = ssh_string_new(ssh_buffer_get_len(kdf_buf)); if (kdf_options == NULL){ ssh_buffer_free(kdf_buf); goto error; } memcpy(ssh_string_data(kdf_options), ssh_buffer_get_begin(kdf_buf), ssh_buffer_get_len(kdf_buf)); ssh_buffer_free(kdf_buf); rc = pki_private_key_encrypt(privkey_buffer, passphrase, "aes128-cbc", "bcrypt", auth_fn, auth_data, rounds, salt); if (rc != SSH_OK){ goto error; } } else { kdf_options = ssh_string_new(0); } rc = ssh_buffer_pack(buffer, "PssSdSdP", (size_t)strlen(OPENSSH_AUTH_MAGIC) + 1, OPENSSH_AUTH_MAGIC, to_encrypt ? "aes128-cbc" : "none", /* ciphername */ to_encrypt ? "bcrypt" : "none", /* kdfname */ kdf_options, /* kdfoptions */ (uint32_t) 1, /* nkeys */ pubkey_s, (uint32_t)ssh_buffer_get_len(privkey_buffer), /* rest of buffer is a string */ (size_t)ssh_buffer_get_len(privkey_buffer), ssh_buffer_get_begin(privkey_buffer)); if (rc != SSH_OK) { goto error; } b64 = bin_to_base64(ssh_buffer_get_begin(buffer), ssh_buffer_get_len(buffer)); if (b64 == NULL){ goto error; } /* we can reuse the buffer */ ssh_buffer_reinit(buffer); rc = ssh_buffer_pack(buffer, "tttttt", OPENSSH_HEADER_BEGIN, "\n", b64, "\n", OPENSSH_HEADER_END, "\n"); BURN_BUFFER(b64, strlen((char *)b64)); SAFE_FREE(b64); if (rc != SSH_OK){ goto error; } str = ssh_string_new(ssh_buffer_get_len(buffer)); if (str == NULL){ goto error; } str_len = ssh_buffer_get_len(buffer); len = buffer_get_data(buffer, ssh_string_data(str), str_len); if (str_len != len) { ssh_string_free(str); str = NULL; } error: if (privkey_buffer != NULL) { void *bufptr = ssh_buffer_get_begin(privkey_buffer); BURN_BUFFER(bufptr, ssh_buffer_get_len(privkey_buffer)); ssh_buffer_free(privkey_buffer); } SAFE_FREE(pubkey_s); SAFE_FREE(kdf_options); SAFE_FREE(salt); if (buffer != NULL) { ssh_buffer_free(buffer); } return str; }