1
1

pki: Implement reading public key from OpenSSH private key container

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
Этот коммит содержится в:
Jakub Jelen 2018-09-13 13:45:46 +02:00 коммит произвёл Andreas Schneider
родитель 2307be32cf
Коммит 1226de875b
3 изменённых файлов: 61 добавлений и 20 удалений

Просмотреть файл

@ -149,6 +149,7 @@ int pki_privkey_build_ed25519(ssh_key key,
ssh_string privkey); ssh_string privkey);
/* PKI Container OpenSSH */ /* PKI Container OpenSSH */
ssh_key ssh_pki_openssh_pubkey_import(const char *text_key);
ssh_key ssh_pki_openssh_privkey_import(const char *text_key, ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
const char *passphrase, ssh_auth_callback auth_fn, void *auth_data); const char *passphrase, ssh_auth_callback auth_fn, void *auth_data);
ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey, ssh_string ssh_pki_openssh_privkey_export(const ssh_key privkey,

Просмотреть файл

@ -1320,7 +1320,7 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
const char *q; const char *q;
FILE *file; FILE *file;
off_t size; off_t size;
int rc; int rc, cmp;
if (pkey == NULL || filename == NULL || *filename == '\0') { if (pkey == NULL || filename == NULL || *filename == '\0') {
return SSH_ERROR; return SSH_ERROR;
@ -1370,6 +1370,20 @@ int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
key_buf[size] = '\0'; key_buf[size] = '\0';
buflen = strlen(key_buf); buflen = strlen(key_buf);
/* Test for new OpenSSH key format first */
cmp = strncmp(key_buf, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN));
if (cmp == 0) {
*pkey = ssh_pki_openssh_pubkey_import(key_buf);
SAFE_FREE(key_buf);
if (*pkey == NULL) {
SSH_LOG(SSH_LOG_WARN, "Failed to import public key from OpenSSH"
" private key file");
return SSH_ERROR;
}
return SSH_OK;
}
/* This the old one-line public key format */
q = p = key_buf; q = p = key_buf;
for (i = 0; i < buflen; i++) { for (i = 0; i < buflen; i++) {
if (isspace((int)p[i])) { if (isspace((int)p[i])) {

Просмотреть файл

@ -30,6 +30,7 @@
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include <stdbool.h>
#include "libssh/libssh.h" #include "libssh/libssh.h"
#include "libssh/priv.h" #include "libssh/priv.h"
@ -225,10 +226,12 @@ static int pki_private_key_decrypt(ssh_string blob,
* @brief Import a private key in OpenSSH (new) format. This format is * @brief Import a private key in OpenSSH (new) format. This format is
* typically used with ed25519 keys but can be used for others. * typically used with ed25519 keys but can be used for others.
*/ */
ssh_key ssh_pki_openssh_privkey_import(const char *text_key, static ssh_key
ssh_pki_openssh_import(const char *text_key,
const char *passphrase, const char *passphrase,
ssh_auth_callback auth_fn, ssh_auth_callback auth_fn,
void *auth_data) void *auth_data,
bool private)
{ {
const char *ptr=text_key; const char *ptr=text_key;
const char *end; const char *end;
@ -249,7 +252,7 @@ ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
cmp = strncmp(ptr, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN)); cmp = strncmp(ptr, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN));
if (cmp != 0){ if (cmp != 0){
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no header)"); SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no header)");
goto error; goto out;
} }
ptr += strlen(OPENSSH_HEADER_BEGIN); ptr += strlen(OPENSSH_HEADER_BEGIN);
while(ptr[0] != '\0' && !isspace((int)ptr[0])) { while(ptr[0] != '\0' && !isspace((int)ptr[0])) {
@ -258,11 +261,11 @@ ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
end = strstr(ptr, OPENSSH_HEADER_END); end = strstr(ptr, OPENSSH_HEADER_END);
if (end == NULL){ if (end == NULL){
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no footer)"); SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (no footer)");
goto error; goto out;
} }
base64 = malloc(end - ptr + 1); base64 = malloc(end - ptr + 1);
if (base64 == NULL){ if (base64 == NULL){
goto error; goto out;
} }
for (i = 0; ptr < end; ptr++){ for (i = 0; ptr < end; ptr++){
if (!isspace((int)ptr[0])) { if (!isspace((int)ptr[0])) {
@ -275,7 +278,7 @@ ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
SAFE_FREE(base64); SAFE_FREE(base64);
if (buffer == NULL){ if (buffer == NULL){
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (base64 error)"); SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (base64 error)");
goto error; goto out;
} }
rc = ssh_buffer_unpack(buffer, "PssSdSS", rc = ssh_buffer_unpack(buffer, "PssSdSS",
strlen(OPENSSH_AUTH_MAGIC) + 1, strlen(OPENSSH_AUTH_MAGIC) + 1,
@ -288,12 +291,12 @@ ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
&privkeys); &privkeys);
if (rc == SSH_ERROR){ if (rc == SSH_ERROR){
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (unpack error)"); SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (unpack error)");
goto error; goto out;
} }
cmp = strncmp(magic, OPENSSH_AUTH_MAGIC, strlen(OPENSSH_AUTH_MAGIC)); cmp = strncmp(magic, OPENSSH_AUTH_MAGIC, strlen(OPENSSH_AUTH_MAGIC));
if (cmp != 0){ if (cmp != 0){
SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (bad magic)"); SSH_LOG(SSH_LOG_WARN, "Not an OpenSSH private key (bad magic)");
goto error; goto out;
} }
SSH_LOG(SSH_LOG_INFO, SSH_LOG(SSH_LOG_INFO,
"Opening OpenSSH private key: ciphername: %s, kdf: %s, nkeys: %d\n", "Opening OpenSSH private key: ciphername: %s, kdf: %s, nkeys: %d\n",
@ -302,8 +305,18 @@ ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
nkeys); nkeys);
if (nkeys != 1){ if (nkeys != 1){
SSH_LOG(SSH_LOG_WARN, "Opening OpenSSH private key: only 1 key supported (%d available)", nkeys); SSH_LOG(SSH_LOG_WARN, "Opening OpenSSH private key: only 1 key supported (%d available)", nkeys);
goto error; goto out;
} }
/* If we are interested only in public key do not progress
* to the key decryption later
*/
if (!private) {
rc = ssh_pki_import_pubkey_blob(pubkey0, &key);
/* in either case we clean up here */
goto out;
}
rc = pki_private_key_decrypt(privkeys, rc = pki_private_key_decrypt(privkeys,
passphrase, passphrase,
ciphername, ciphername,
@ -312,13 +325,13 @@ ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
auth_fn, auth_fn,
auth_data); auth_data);
if (rc == SSH_ERROR){ if (rc == SSH_ERROR){
goto error; goto out;
} }
privkey_buffer = ssh_buffer_new(); privkey_buffer = ssh_buffer_new();
if (privkey_buffer == NULL) { if (privkey_buffer == NULL) {
rc = SSH_ERROR; rc = SSH_ERROR;
goto error; goto out;
} }
ssh_buffer_set_secure(privkey_buffer); ssh_buffer_set_secure(privkey_buffer);
@ -329,11 +342,11 @@ ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
rc = ssh_buffer_unpack(privkey_buffer, "dd", &checkint1, &checkint2); rc = ssh_buffer_unpack(privkey_buffer, "dd", &checkint1, &checkint2);
if (rc == SSH_ERROR || checkint1 != checkint2){ if (rc == SSH_ERROR || checkint1 != checkint2){
SSH_LOG(SSH_LOG_WARN, "OpenSSH private key unpack error (correct password?)"); SSH_LOG(SSH_LOG_WARN, "OpenSSH private key unpack error (correct password?)");
goto error; goto out;
} }
rc = pki_openssh_import_privkey_blob(privkey_buffer, &key); rc = pki_openssh_import_privkey_blob(privkey_buffer, &key);
if (rc == SSH_ERROR){ if (rc == SSH_ERROR){
goto error; goto out;
} }
comment = ssh_buffer_get_ssh_string(privkey_buffer); comment = ssh_buffer_get_ssh_string(privkey_buffer);
SAFE_FREE(comment); SAFE_FREE(comment);
@ -344,10 +357,10 @@ ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
ssh_key_free(key); ssh_key_free(key);
key = NULL; key = NULL;
SSH_LOG(SSH_LOG_WARN, "Invalid padding"); SSH_LOG(SSH_LOG_WARN, "Invalid padding");
goto error; goto out;
} }
} }
error: out:
if (buffer != NULL) { if (buffer != NULL) {
ssh_buffer_free(buffer); ssh_buffer_free(buffer);
buffer = NULL; buffer = NULL;
@ -365,6 +378,19 @@ error:
return key; return key;
} }
ssh_key ssh_pki_openssh_privkey_import(const char *text_key,
const char *passphrase,
ssh_auth_callback auth_fn,
void *auth_data)
{
return ssh_pki_openssh_import(text_key, passphrase, auth_fn, auth_data, true);
}
ssh_key ssh_pki_openssh_pubkey_import(const char *text_key)
{
return ssh_pki_openssh_import(text_key, NULL, NULL, NULL, false);
}
/** @internal /** @internal
* @brief exports a private key to a string blob. * @brief exports a private key to a string blob.