Blame src/pki.c

Packit Service 31306d
/*
Packit Service 31306d
 * pki.c
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2010 by Aris Adamantiadis
Packit Service 31306d
 * Copyright (c) 2011-2013 Andreas Schneider <asn@cryptomilk.org>
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is free software; you can redistribute it and/or modify
Packit Service 31306d
 * it under the terms of the GNU Lesser General Public License as published by
Packit Service 31306d
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit Service 31306d
 * option) any later version.
Packit Service 31306d
 *
Packit Service 31306d
 * The SSH Library is distributed in the hope that it will be useful, but
Packit Service 31306d
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit Service 31306d
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit Service 31306d
 * License for more details.
Packit Service 31306d
 *
Packit Service 31306d
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 31306d
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit Service 31306d
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit Service 31306d
 * MA 02111-1307, USA.
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @defgroup libssh_pki The SSH Public Key Infrastructure
Packit Service 31306d
 * @ingroup libssh
Packit Service 31306d
 *
Packit Service 31306d
 * Functions for the creation, importation and manipulation of public and
Packit Service 31306d
 * private keys in the context of the SSH protocol
Packit Service 31306d
 *
Packit Service 31306d
 * @{
Packit Service 31306d
 */
Packit Service 31306d
Packit Service 31306d
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include <errno.h>
Packit Service 31306d
#include <ctype.h>
Packit Service 31306d
#include <stdio.h>
Packit Service 31306d
#include <fcntl.h>
Packit Service 31306d
#include <sys/stat.h>
Packit Service 31306d
#include <sys/types.h>
Packit Service 31306d
Packit Service 31306d
#ifdef _WIN32
Packit Service 31306d
# ifdef HAVE_IO_H
Packit Service 31306d
#  include <io.h>
Packit Service 31306d
#  undef open
Packit Service 31306d
#  define open _open
Packit Service 31306d
#  undef close
Packit Service 31306d
#  define close _close
Packit Service 31306d
#  undef read
Packit Service 31306d
#  define read _read
Packit Service 31306d
#  undef unlink
Packit Service 31306d
#  define unlink _unlink
Packit Service 31306d
# endif /* HAVE_IO_H */
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
#include "libssh/libssh.h"
Packit Service 31306d
#include "libssh/session.h"
Packit Service 31306d
#include "libssh/priv.h"
Packit Service 31306d
#include "libssh/pki.h"
Packit Service 31306d
#include "libssh/pki_priv.h"
Packit Service 31306d
#include "libssh/keys.h"
Packit Service 31306d
#include "libssh/buffer.h"
Packit Service 31306d
#include "libssh/misc.h"
Packit Service 31306d
#include "libssh/agent.h"
Packit Service 31306d
Packit Service 31306d
enum ssh_keytypes_e pki_privatekey_type_from_string(const char *privkey)
Packit Service 31306d
{
Packit Service 31306d
    char *start = NULL;
Packit Service 31306d
Packit Service 31306d
    start = strstr(privkey, DSA_HEADER_BEGIN);
Packit Service 31306d
    if (start != NULL) {
Packit Service 31306d
        return SSH_KEYTYPE_DSS;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    start = strstr(privkey, RSA_HEADER_BEGIN);
Packit Service 31306d
    if (start != NULL) {
Packit Service 31306d
        return SSH_KEYTYPE_RSA;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    start = strstr(privkey, ECDSA_HEADER_BEGIN);
Packit Service 31306d
    if (start != 0) {
Packit Service 31306d
        /* We don't know what the curve is at this point, so we don't actually
Packit Service 31306d
         * know the type. We figure out the actual curve and fix things up in
Packit Service 31306d
         * pki_private_key_from_base64 */
Packit Service 31306d
        return SSH_KEYTYPE_ECDSA_P256;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_KEYTYPE_UNKNOWN;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief returns the ECDSA key name ("ecdsa-sha2-nistp256" for example)
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] key the ssh_key whose ECDSA name to get
Packit Service 31306d
 *
Packit Service 31306d
 * @returns the ECDSA key name ("ecdsa-sha2-nistp256" for example)
Packit Service 31306d
 *
Packit Service 31306d
 * @returns "unknown" if the ECDSA key name is not known
Packit Service 31306d
 */
Packit Service 31306d
const char *ssh_pki_key_ecdsa_name(const ssh_key key)
Packit Service 31306d
{
Packit Service 31306d
    if (key == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_ECC /* FIXME Better ECC check needed */
Packit Service 31306d
    return pki_key_ecdsa_nid_to_name(key->ecdsa_nid);
Packit Service 31306d
#else
Packit Service 31306d
    return NULL;
Packit Service 31306d
#endif
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief creates a new empty SSH key
Packit Service 31306d
 * @returns an empty ssh_key handle, or NULL on error.
Packit Service 31306d
 */
Packit Service 31306d
ssh_key ssh_key_new (void) {
Packit Service 31306d
  ssh_key ptr = malloc (sizeof (struct ssh_key_struct));
Packit Service 31306d
  if (ptr == NULL) {
Packit Service 31306d
      return NULL;
Packit Service 31306d
  }
Packit Service 31306d
  ZERO_STRUCTP(ptr);
Packit Service 31306d
  return ptr;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
ssh_key ssh_key_dup(const ssh_key key)
Packit Service 31306d
{
Packit Service 31306d
    if (key == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return pki_key_dup(key, 0);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief clean up the key and deallocate all existing keys
Packit Service 31306d
 * @param[in] key ssh_key to clean
Packit Service 31306d
 */
Packit Service 31306d
void ssh_key_clean (ssh_key key){
Packit Service 31306d
    if(key == NULL)
Packit Service 31306d
        return;
Packit Service 31306d
#ifdef HAVE_LIBGCRYPT
Packit Service 31306d
    if(key->dsa) gcry_sexp_release(key->dsa);
Packit Service 31306d
    if(key->rsa) gcry_sexp_release(key->rsa);
Packit Service 31306d
    if(key->ecdsa) gcry_sexp_release(key->ecdsa);
Packit Service 31306d
#elif defined HAVE_LIBCRYPTO
Packit Service 31306d
    if(key->dsa) DSA_free(key->dsa);
Packit Service 31306d
    if(key->rsa) RSA_free(key->rsa);
Packit Service 31306d
#ifdef HAVE_OPENSSL_ECC
Packit Service 31306d
    if(key->ecdsa) EC_KEY_free(key->ecdsa);
Packit Service 31306d
#endif /* HAVE_OPENSSL_ECC */
Packit Service 31306d
#elif defined HAVE_LIBMBEDCRYPTO
Packit Service 31306d
    if (key->rsa != NULL) {
Packit Service 31306d
        mbedtls_pk_free(key->rsa);
Packit Service 31306d
        SAFE_FREE(key->rsa);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (key->ecdsa != NULL) {
Packit Service 31306d
        mbedtls_ecdsa_free(key->ecdsa);
Packit Service 31306d
        SAFE_FREE(key->ecdsa);
Packit Service 31306d
    }
Packit Service 31306d
#endif
Packit Service 31306d
    if (key->ed25519_privkey != NULL){
Packit Service 31306d
#ifdef HAVE_OPENSSL_ED25519
Packit Service 31306d
        /* In OpenSSL implementation the private key is only the private
Packit Service 31306d
         * original seed. In the internal implementation the private key is the
Packit Service 31306d
         * concatenation of the original private seed with the public key.*/
Packit Service 31306d
        explicit_bzero(key->ed25519_privkey, ED25519_KEY_LEN);
Packit Service 31306d
#else
Packit Service 31306d
        explicit_bzero(key->ed25519_privkey, sizeof(ed25519_privkey));
Packit Service 31306d
#endif
Packit Service 31306d
        SAFE_FREE(key->ed25519_privkey);
Packit Service 31306d
    }
Packit Service 31306d
    SAFE_FREE(key->ed25519_pubkey);
Packit Service 31306d
    if (key->cert != NULL) {
Packit Service 31306d
        SSH_BUFFER_FREE(key->cert);
Packit Service 31306d
    }
Packit Service 31306d
    key->cert_type = SSH_KEYTYPE_UNKNOWN;
Packit Service 31306d
    key->flags=SSH_KEY_FLAG_EMPTY;
Packit Service 31306d
    key->type=SSH_KEYTYPE_UNKNOWN;
Packit Service 31306d
    key->ecdsa_nid = 0;
Packit Service 31306d
    key->type_c=NULL;
Packit Service 31306d
    key->dsa = NULL;
Packit Service 31306d
    key->rsa = NULL;
Packit Service 31306d
    key->ecdsa = NULL;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief deallocate a SSH key
Packit Service 31306d
 * @param[in] key ssh_key handle to free
Packit Service 31306d
 */
Packit Service 31306d
void ssh_key_free (ssh_key key){
Packit Service 31306d
    if(key){
Packit Service 31306d
        ssh_key_clean(key);
Packit Service 31306d
        SAFE_FREE(key);
Packit Service 31306d
    }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief returns the type of a ssh key
Packit Service 31306d
 * @param[in] key the ssh_key handle
Packit Service 31306d
 * @returns one of SSH_KEYTYPE_RSA, SSH_KEYTYPE_DSS,
Packit Service 31306d
 *          SSH_KEYTYPE_ECDSA_P256, SSH_KEYTYPE_ECDSA_P384,
Packit Service 31306d
 *          SSH_KEYTYPE_ECDSA_P521, SSH_KEYTYPE_ED25519, SSH_KEYTYPE_DSS_CERT01,
Packit Service 31306d
 *          SSH_KEYTYPE_RSA_CERT01, SSH_KEYTYPE_ECDSA_P256_CERT01,
Packit Service 31306d
 *          SSH_KEYTYPE_ECDSA_P384_CERT01, SSH_KEYTYPE_ECDSA_P521_CERT01, or
Packit Service 31306d
 *          SSH_KEYTYPE_ED25519_CERT01.
Packit Service 31306d
 * @returns SSH_KEYTYPE_UNKNOWN if the type is unknown
Packit Service 31306d
 */
Packit Service 31306d
enum ssh_keytypes_e ssh_key_type(const ssh_key key){
Packit Service 31306d
    if (key == NULL) {
Packit Service 31306d
        return SSH_KEYTYPE_UNKNOWN;
Packit Service 31306d
    }
Packit Service 31306d
    return key->type;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Convert a signature type to a string.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  type     The algorithm type to convert.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              A string for the keytype or NULL if unknown.
Packit Service 31306d
 */
Packit Service 31306d
const char *
Packit Service 31306d
ssh_key_signature_to_char(enum ssh_keytypes_e type,
Packit Service 31306d
                          enum ssh_digest_e hash_type)
Packit Service 31306d
{
Packit Service 31306d
    switch (type) {
Packit Service 31306d
    case SSH_KEYTYPE_RSA:
Packit Service 31306d
        switch (hash_type) {
Packit Service 31306d
        case SSH_DIGEST_SHA256:
Packit Service 31306d
            return "rsa-sha2-256";
Packit Service 31306d
        case SSH_DIGEST_SHA512:
Packit Service 31306d
            return "rsa-sha2-512";
Packit Service 31306d
        case SSH_DIGEST_SHA1:
Packit Service 31306d
        case SSH_DIGEST_AUTO:
Packit Service 31306d
            return "ssh-rsa";
Packit Service 31306d
        default:
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
        switch (hash_type) {
Packit Service 31306d
        case SSH_DIGEST_SHA256:
Packit Service 31306d
            return "rsa-sha2-256-cert-v01@openssh.com";
Packit Service 31306d
        case SSH_DIGEST_SHA512:
Packit Service 31306d
            return "rsa-sha2-512-cert-v01@openssh.com";
Packit Service 31306d
        case SSH_DIGEST_SHA1:
Packit Service 31306d
        case SSH_DIGEST_AUTO:
Packit Service 31306d
            return "ssh-rsa-cert-v01@openssh.com";
Packit Service 31306d
        default:
Packit Service 31306d
            return NULL;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    default:
Packit Service 31306d
        return ssh_key_type_to_char(type);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* We should never reach this */
Packit Service 31306d
    return NULL;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Convert a key type to a string.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  type     The type to convert.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              A string for the keytype or NULL if unknown.
Packit Service 31306d
 */
Packit Service 31306d
const char *ssh_key_type_to_char(enum ssh_keytypes_e type) {
Packit Service 31306d
  switch (type) {
Packit Service 31306d
    case SSH_KEYTYPE_DSS:
Packit Service 31306d
      return "ssh-dss";
Packit Service 31306d
    case SSH_KEYTYPE_RSA:
Packit Service 31306d
      return "ssh-rsa";
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA:
Packit Service 31306d
      return "ssh-ecdsa"; /* deprecated. invalid value */
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
      return "ecdsa-sha2-nistp256";
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
      return "ecdsa-sha2-nistp384";
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
      return "ecdsa-sha2-nistp521";
Packit Service 31306d
    case SSH_KEYTYPE_ED25519:
Packit Service 31306d
      return "ssh-ed25519";
Packit Service 31306d
    case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
      return "ssh-dss-cert-v01@openssh.com";
Packit Service 31306d
    case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
      return "ssh-rsa-cert-v01@openssh.com";
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
      return "ecdsa-sha2-nistp256-cert-v01@openssh.com";
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
      return "ecdsa-sha2-nistp384-cert-v01@openssh.com";
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
      return "ecdsa-sha2-nistp521-cert-v01@openssh.com";
Packit Service 31306d
    case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
      return "ssh-ed25519-cert-v01@openssh.com";
Packit Service 31306d
    case SSH_KEYTYPE_RSA1:
Packit Service 31306d
    case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
      return NULL;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  /* We should never reach this */
Packit Service 31306d
  return NULL;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
enum ssh_digest_e ssh_key_hash_from_name(const char *name)
Packit Service 31306d
{
Packit Service 31306d
    if (name == NULL) {
Packit Service 31306d
        /* TODO we should rather fail */
Packit Service 31306d
        return SSH_DIGEST_AUTO;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (strcmp(name, "ssh-rsa") == 0) {
Packit Service 31306d
        return SSH_DIGEST_SHA1;
Packit Service 31306d
    } else if (strcmp(name, "ssh-dss") == 0) {
Packit Service 31306d
        return SSH_DIGEST_SHA1;
Packit Service 31306d
    } else if (strcmp(name, "rsa-sha2-256") == 0) {
Packit Service 31306d
        return SSH_DIGEST_SHA256;
Packit Service 31306d
    } else if (strcmp(name, "rsa-sha2-512") == 0) {
Packit Service 31306d
        return SSH_DIGEST_SHA512;
Packit Service 31306d
    } else if (strcmp(name, "ecdsa-sha2-nistp256") == 0) {
Packit Service 31306d
        return SSH_DIGEST_SHA256;
Packit Service 31306d
    } else if (strcmp(name, "ecdsa-sha2-nistp384") == 0) {
Packit Service 31306d
        return SSH_DIGEST_SHA384;
Packit Service 31306d
    } else if (strcmp(name, "ecdsa-sha2-nistp521") == 0) {
Packit Service 31306d
        return SSH_DIGEST_SHA512;
Packit Service 31306d
    } else if (strcmp(name, "ssh-ed25519") == 0) {
Packit Service 31306d
        return SSH_DIGEST_AUTO;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_WARN, "Unknown signature name %s", name);
Packit Service 31306d
Packit Service 31306d
    /* TODO we should rather fail */
Packit Service 31306d
    return SSH_DIGEST_AUTO;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Checks the given key against the configured allowed
Packit Service 31306d
 * public key algorithm types
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] session The SSH session
Packit Service 31306d
 * @param[in] type    The key algorithm to check
Packit Service 31306d
 * @returns           1 if the key algorithm is allowed, 0 otherwise
Packit Service 31306d
 */
Packit Service 31306d
int ssh_key_algorithm_allowed(ssh_session session, const char *type)
Packit Service 31306d
{
Packit Service 31306d
    const char *allowed_list;
Packit Service 31306d
Packit Service 31306d
    if (session->client) {
Packit Service 31306d
        allowed_list = session->opts.pubkey_accepted_types;
Packit Service 31306d
        if (allowed_list == NULL) {
Packit Service 31306d
            if (ssh_fips_mode()) {
Packit Service 31306d
                allowed_list = ssh_kex_get_fips_methods(SSH_HOSTKEYS);
Packit Service 31306d
            } else {
Packit Service 31306d
                allowed_list = ssh_kex_get_default_methods(SSH_HOSTKEYS);
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
#ifdef WITH_SERVER
Packit Service 31306d
    else if (session->server) {
Packit Service 31306d
        allowed_list = session->opts.wanted_methods[SSH_HOSTKEYS];
Packit Service 31306d
        if (allowed_list == NULL) {
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARN, "Session invalid: no host key available");
Packit Service 31306d
            return 0;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
#endif
Packit Service 31306d
    else {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Session invalid: not set as client nor server");
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_DEBUG, "Checking %s with list <%s>", type, allowed_list);
Packit Service 31306d
    return ssh_match_group(allowed_list, type);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Convert a key type to a hash type. This is usually unambiguous
Packit Service 31306d
 * for all the key types, unless the SHA2 extension (RFC 8332) is
Packit Service 31306d
 * negotiated during key exchange.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  session  SSH Session.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  type     The type to convert.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              A hash type to be used.
Packit Service 31306d
 */
Packit Service 31306d
enum ssh_digest_e ssh_key_type_to_hash(ssh_session session,
Packit Service 31306d
                                       enum ssh_keytypes_e type)
Packit Service 31306d
{
Packit Service 31306d
    switch (type) {
Packit Service 31306d
    case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_DSS:
Packit Service 31306d
        return SSH_DIGEST_SHA1;
Packit Service 31306d
    case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
        /* If we are talking to an old OpenSSH version which does not support
Packit Service 31306d
         * SHA2 in certificates */
Packit Service 31306d
        if ((session->openssh > 0) &&
Packit Service 31306d
            (session->openssh < SSH_VERSION_INT(7, 2, 0)))
Packit Service 31306d
        {
Packit Service 31306d
            SSH_LOG(SSH_LOG_DEBUG,
Packit Service 31306d
                    "We are talking to an old OpenSSH (%x); "
Packit Service 31306d
                    "returning SSH_DIGEST_SHA1",
Packit Service 31306d
                    session->openssh);
Packit Service 31306d
Packit Service 31306d
            return SSH_DIGEST_SHA1;
Packit Service 31306d
        }
Packit Service 31306d
        FALL_THROUGH;
Packit Service 31306d
    case SSH_KEYTYPE_RSA:
Packit Service 31306d
        if (ssh_key_algorithm_allowed(session, "rsa-sha2-512") &&
Packit Service 31306d
            (session->extensions & SSH_EXT_SIG_RSA_SHA512)) {
Packit Service 31306d
            return SSH_DIGEST_SHA512;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (ssh_key_algorithm_allowed(session, "rsa-sha2-256") &&
Packit Service 31306d
            (session->extensions & SSH_EXT_SIG_RSA_SHA256)) {
Packit Service 31306d
            return SSH_DIGEST_SHA256;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        /* Default algorithm for RSA is SHA1 */
Packit Service 31306d
        return SSH_DIGEST_SHA1;
Packit Service 31306d
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        return SSH_DIGEST_SHA256;
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        return SSH_DIGEST_SHA384;
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
        return SSH_DIGEST_SHA512;
Packit Service 31306d
    case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_ED25519:
Packit Service 31306d
        return SSH_DIGEST_AUTO;
Packit Service 31306d
    case SSH_KEYTYPE_RSA1:
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA:
Packit Service 31306d
    case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
    default:
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Digest algorithm to be used with key type %u "
Packit Service 31306d
                "is not defined", type);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* We should never reach this */
Packit Service 31306d
    return SSH_DIGEST_AUTO;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Gets signature algorithm name to be used with the given
Packit Service 31306d
 *        key type.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  session  SSH session.
Packit Service 31306d
 * @param[in]  type     The algorithm type to convert.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              A string for the keytype or NULL if unknown.
Packit Service 31306d
 */
Packit Service 31306d
const char *
Packit Service 31306d
ssh_key_get_signature_algorithm(ssh_session session,
Packit Service 31306d
                                enum ssh_keytypes_e type)
Packit Service 31306d
{
Packit Service 31306d
    enum ssh_digest_e hash_type;
Packit Service 31306d
Packit Service 31306d
    if (type == SSH_KEYTYPE_RSA_CERT01) {
Packit Service 31306d
        /* If we are talking to an old OpenSSH version which does not support
Packit Service 31306d
         * rsa-sha2-{256,512}-cert-v01@openssh.com */
Packit Service 31306d
        if ((session->openssh > 0) &&
Packit Service 31306d
            (session->openssh < SSH_VERSION_INT(7, 8, 0)))
Packit Service 31306d
        {
Packit Service 31306d
            SSH_LOG(SSH_LOG_DEBUG,
Packit Service 31306d
                    "We are talking to an old OpenSSH (%x); "
Packit Service 31306d
                    "using old cert format",
Packit Service 31306d
                    session->openssh);
Packit Service 31306d
Packit Service 31306d
            return "ssh-rsa-cert-v01@openssh.com";
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    hash_type = ssh_key_type_to_hash(session, type);
Packit Service 31306d
Packit Service 31306d
    return ssh_key_signature_to_char(type, hash_type);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Convert a ssh key algorithm name to a ssh key algorithm type.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] name      The name to convert.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              The enum ssh key algorithm type.
Packit Service 31306d
 */
Packit Service 31306d
enum ssh_keytypes_e ssh_key_type_from_signature_name(const char *name) {
Packit Service 31306d
    if (name == NULL) {
Packit Service 31306d
        return SSH_KEYTYPE_UNKNOWN;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if ((strcmp(name, "rsa-sha2-256") == 0) ||
Packit Service 31306d
        (strcmp(name, "rsa-sha2-512") == 0)) {
Packit Service 31306d
        return SSH_KEYTYPE_RSA;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Otherwise the key type matches the signature type */
Packit Service 31306d
    return ssh_key_type_from_name(name);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Convert a ssh key name to a ssh key type.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] name      The name to convert.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              The enum ssh key type.
Packit Service 31306d
 */
Packit Service 31306d
enum ssh_keytypes_e ssh_key_type_from_name(const char *name) {
Packit Service 31306d
    if (name == NULL) {
Packit Service 31306d
        return SSH_KEYTYPE_UNKNOWN;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (strcmp(name, "rsa") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_RSA;
Packit Service 31306d
    } else if (strcmp(name, "dsa") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_DSS;
Packit Service 31306d
    } else if (strcmp(name, "ssh-rsa") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_RSA;
Packit Service 31306d
    } else if (strcmp(name, "ssh-dss") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_DSS;
Packit Service 31306d
    } else if (strcmp(name, "ssh-ecdsa") == 0
Packit Service 31306d
            || strcmp(name, "ecdsa") == 0
Packit Service 31306d
            || strcmp(name, "ecdsa-sha2-nistp256") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_ECDSA_P256;
Packit Service 31306d
    } else if (strcmp(name, "ecdsa-sha2-nistp384") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_ECDSA_P384;
Packit Service 31306d
    } else if (strcmp(name, "ecdsa-sha2-nistp521") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_ECDSA_P521;
Packit Service 31306d
    } else if (strcmp(name, "ssh-ed25519") == 0){
Packit Service 31306d
        return SSH_KEYTYPE_ED25519;
Packit Service 31306d
    } else if (strcmp(name, "ssh-dss-cert-v01@openssh.com") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_DSS_CERT01;
Packit Service 31306d
    } else if (strcmp(name, "ssh-rsa-cert-v01@openssh.com") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_RSA_CERT01;
Packit Service 31306d
    } else if (strcmp(name, "ecdsa-sha2-nistp256-cert-v01@openssh.com") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_ECDSA_P256_CERT01;
Packit Service 31306d
    } else if (strcmp(name, "ecdsa-sha2-nistp384-cert-v01@openssh.com") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_ECDSA_P384_CERT01;
Packit Service 31306d
    } else if (strcmp(name, "ecdsa-sha2-nistp521-cert-v01@openssh.com") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_ECDSA_P521_CERT01;
Packit Service 31306d
    } else if (strcmp(name, "ssh-ed25519-cert-v01@openssh.com") == 0) {
Packit Service 31306d
        return SSH_KEYTYPE_ED25519_CERT01;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return SSH_KEYTYPE_UNKNOWN;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Get the pubic key type corresponding to a certificate type.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] type   The certificate or public key type.
Packit Service 31306d
 *
Packit Service 31306d
 * @return           The matching public key type.
Packit Service 31306d
 */
Packit Service 31306d
enum ssh_keytypes_e ssh_key_type_plain(enum ssh_keytypes_e type) {
Packit Service 31306d
    switch (type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
            return SSH_KEYTYPE_DSS;
Packit Service 31306d
        case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
            return SSH_KEYTYPE_RSA;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
            return SSH_KEYTYPE_ECDSA_P256;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
            return SSH_KEYTYPE_ECDSA_P384;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
            return SSH_KEYTYPE_ECDSA_P521;
Packit Service 31306d
        case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
            return SSH_KEYTYPE_ED25519;
Packit Service 31306d
        default:
Packit Service 31306d
            return type;
Packit Service 31306d
    }
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Check if the key has/is a public key.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] k         The key to check.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              1 if it is a public key, 0 if not.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_key_is_public(const ssh_key k) {
Packit Service 31306d
    if (k == NULL) {
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return (k->flags & SSH_KEY_FLAG_PUBLIC) == SSH_KEY_FLAG_PUBLIC;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Check if the key is a private key.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] k         The key to check.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              1 if it is a private key, 0 if not.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_key_is_private(const ssh_key k) {
Packit Service 31306d
    if (k == NULL) {
Packit Service 31306d
        return 0;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return (k->flags & SSH_KEY_FLAG_PRIVATE) == SSH_KEY_FLAG_PRIVATE;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Compare keys if they are equal.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] k1        The first key to compare.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] k2        The second key to compare.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] what      What part or type of the key do you want to compare.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              0 if equal, 1 if not.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_key_cmp(const ssh_key k1,
Packit Service 31306d
                const ssh_key k2,
Packit Service 31306d
                enum ssh_keycmp_e what)
Packit Service 31306d
{
Packit Service 31306d
    if (k1 == NULL || k2 == NULL) {
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (k1->type != k2->type) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "key types don't match!");
Packit Service 31306d
        return 1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (what == SSH_KEY_CMP_PRIVATE) {
Packit Service 31306d
        if (!ssh_key_is_private(k1) ||
Packit Service 31306d
            !ssh_key_is_private(k2)) {
Packit Service 31306d
            return 1;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (k1->type == SSH_KEYTYPE_ED25519) {
Packit Service 31306d
        return pki_ed25519_key_cmp(k1, k2, what);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return pki_key_compare(k1, k2, what);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
ssh_signature ssh_signature_new(void)
Packit Service 31306d
{
Packit Service 31306d
    struct ssh_signature_struct *sig;
Packit Service 31306d
Packit Service 31306d
    sig = malloc(sizeof(struct ssh_signature_struct));
Packit Service 31306d
    if (sig == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
    ZERO_STRUCTP(sig);
Packit Service 31306d
Packit Service 31306d
    return sig;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
void ssh_signature_free(ssh_signature sig)
Packit Service 31306d
{
Packit Service 31306d
    if (sig == NULL) {
Packit Service 31306d
        return;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch(sig->type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
#ifdef HAVE_LIBGCRYPT
Packit Service 31306d
            gcry_sexp_release(sig->dsa_sig);
Packit Service 31306d
#endif
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
#ifdef HAVE_LIBGCRYPT
Packit Service 31306d
            gcry_sexp_release(sig->rsa_sig);
Packit Service 31306d
#elif defined HAVE_LIBMBEDCRYPTO
Packit Service 31306d
            SAFE_FREE(sig->rsa_sig);
Packit Service 31306d
#endif
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
#ifdef HAVE_GCRYPT_ECC
Packit Service 31306d
            gcry_sexp_release(sig->ecdsa_sig);
Packit Service 31306d
#elif defined HAVE_LIBMBEDCRYPTO
Packit Service 31306d
            bignum_safe_free(sig->ecdsa_sig.r);
Packit Service 31306d
            bignum_safe_free(sig->ecdsa_sig.s);
Packit Service 31306d
#endif
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
#ifndef HAVE_OPENSSL_ED25519
Packit Service 31306d
            /* When using OpenSSL, the signature is stored in sig->raw_sig */
Packit Service 31306d
            SAFE_FREE(sig->ed25519_sig);
Packit Service 31306d
#endif
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
            break;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Explicitly zero the signature content before free */
Packit Service 31306d
    ssh_string_burn(sig->raw_sig);
Packit Service 31306d
    SSH_STRING_FREE(sig->raw_sig);
Packit Service 31306d
    SAFE_FREE(sig);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief import a base64 formated key from a memory c-string
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  b64_key  The c-string holding the base64 encoded key
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  passphrase The passphrase to decrypt the key, or NULL
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  auth_fn  An auth function you may want to use or NULL.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  auth_data Private data passed to the auth function.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] pkey     A pointer where the allocated key can be stored. You
Packit Service 31306d
 *                      need to free the memory.
Packit Service 31306d
 *
Packit Service 31306d
 * @return  SSH_ERROR in case of error, SSH_OK otherwise.
Packit Service 31306d
 *
Packit Service 31306d
 * @see ssh_key_free()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_import_privkey_base64(const char *b64_key,
Packit Service 31306d
                                  const char *passphrase,
Packit Service 31306d
                                  ssh_auth_callback auth_fn,
Packit Service 31306d
                                  void *auth_data,
Packit Service 31306d
                                  ssh_key *pkey)
Packit Service 31306d
{
Packit Service 31306d
    ssh_key key;
Packit Service 31306d
    char *openssh_header = NULL;
Packit Service 31306d
Packit Service 31306d
    if (b64_key == NULL || pkey == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (b64_key == NULL || !*b64_key) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_INFO,
Packit Service 31306d
            "Trying to decode privkey passphrase=%s",
Packit Service 31306d
            passphrase ? "true" : "false");
Packit Service 31306d
Packit Service 31306d
    /* Test for OpenSSH key format first */
Packit Service 31306d
    openssh_header = strstr(b64_key, OPENSSH_HEADER_BEGIN);
Packit Service 31306d
    if (openssh_header != NULL) {
Packit Service 31306d
        key = ssh_pki_openssh_privkey_import(openssh_header,
Packit Service 31306d
                                             passphrase,
Packit Service 31306d
                                             auth_fn,
Packit Service 31306d
                                             auth_data);
Packit Service 31306d
    } else {
Packit Service 31306d
        /* fallback on PEM decoder */
Packit Service 31306d
        key = pki_private_key_from_base64(b64_key,
Packit Service 31306d
                                          passphrase,
Packit Service 31306d
                                          auth_fn,
Packit Service 31306d
                                          auth_data);
Packit Service 31306d
    }
Packit Service 31306d
    if (key == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    *pkey = key;
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
 /**
Packit Service 31306d
 * @brief Convert a private key to a pem base64 encoded key, or OpenSSH format for
Packit Service 31306d
 *        keytype ssh-ed25519
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  privkey  The private key to export.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  passphrase The passphrase to use to encrypt the key with or
Packit Service 31306d
 *             NULL. An empty string means no passphrase.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  auth_fn  An auth function you may want to use or NULL.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  auth_data Private data passed to the auth function.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] b64_key  A pointer to store the allocated base64 encoded key. You
Packit Service 31306d
 *                      need to free the buffer.
Packit Service 31306d
 *
Packit Service 31306d
 * @return     SSH_OK on success, SSH_ERROR on error.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_export_privkey_base64(const ssh_key privkey,
Packit Service 31306d
                                  const char *passphrase,
Packit Service 31306d
                                  ssh_auth_callback auth_fn,
Packit Service 31306d
                                  void *auth_data,
Packit Service 31306d
                                  char **b64_key)
Packit Service 31306d
{
Packit Service 31306d
    ssh_string blob = NULL;
Packit Service 31306d
    char *b64 = NULL;
Packit Service 31306d
Packit Service 31306d
    if (privkey == NULL || !ssh_key_is_private(privkey)) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (privkey->type == SSH_KEYTYPE_ED25519){
Packit Service 31306d
        blob = ssh_pki_openssh_privkey_export(privkey,
Packit Service 31306d
                                              passphrase,
Packit Service 31306d
                                              auth_fn,
Packit Service 31306d
                                              auth_data);
Packit Service 31306d
    } else {
Packit Service 31306d
        blob = pki_private_key_to_pem(privkey,
Packit Service 31306d
                                      passphrase,
Packit Service 31306d
                                      auth_fn,
Packit Service 31306d
                                      auth_data);
Packit Service 31306d
    }
Packit Service 31306d
    if (blob == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    b64 = strndup(ssh_string_data(blob), ssh_string_len(blob));
Packit Service 31306d
    SSH_STRING_FREE(blob);
Packit Service 31306d
    if (b64 == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    *b64_key = b64;
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Import a key from a file.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  filename The filename of the the private key.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  passphrase The passphrase to decrypt the private key. Set to NULL
Packit Service 31306d
 *                        if none is needed or it is unknown.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  auth_fn  An auth function you may want to use or NULL.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  auth_data Private data passed to the auth function.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] pkey     A pointer to store the allocated ssh_key. You need to
Packit Service 31306d
 *                      free the key.
Packit Service 31306d
 *
Packit Service 31306d
 * @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
Packit Service 31306d
 *          denied, SSH_ERROR otherwise.
Packit Service 31306d
 *
Packit Service 31306d
 * @see ssh_key_free()
Packit Service 31306d
 **/
Packit Service 31306d
int ssh_pki_import_privkey_file(const char *filename,
Packit Service 31306d
                                const char *passphrase,
Packit Service 31306d
                                ssh_auth_callback auth_fn,
Packit Service 31306d
                                void *auth_data,
Packit Service 31306d
                                ssh_key *pkey) {
Packit Service 31306d
    struct stat sb;
Packit Service 31306d
    char *key_buf;
Packit Service 31306d
    FILE *file;
Packit Service 31306d
    off_t size;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (pkey == NULL || filename == NULL || *filename == '\0') {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    file = fopen(filename, "rb");
Packit Service 31306d
    if (file == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                "Error opening %s: %s",
Packit Service 31306d
                filename,
Packit Service 31306d
                strerror(errno));
Packit Service 31306d
        return SSH_EOF;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = fstat(fileno(file), &sb);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        fclose(file);
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                "Error getting stat of %s: %s",
Packit Service 31306d
                filename,
Packit Service 31306d
                strerror(errno));
Packit Service 31306d
        switch (errno) {
Packit Service 31306d
            case ENOENT:
Packit Service 31306d
            case EACCES:
Packit Service 31306d
                return SSH_EOF;
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (sb.st_size > MAX_PRIVKEY_SIZE) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                "Private key is bigger than 4M.");
Packit Service 31306d
        fclose(file);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    key_buf = malloc(sb.st_size + 1);
Packit Service 31306d
    if (key_buf == NULL) {
Packit Service 31306d
        fclose(file);
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Out of memory!");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    size = fread(key_buf, 1, sb.st_size, file);
Packit Service 31306d
    fclose(file);
Packit Service 31306d
Packit Service 31306d
    if (size != sb.st_size) {
Packit Service 31306d
        SAFE_FREE(key_buf);
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                "Error reading %s: %s",
Packit Service 31306d
                filename,
Packit Service 31306d
                strerror(errno));
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    key_buf[size] = 0;
Packit Service 31306d
Packit Service 31306d
    rc = ssh_pki_import_privkey_base64(key_buf,
Packit Service 31306d
                                       passphrase,
Packit Service 31306d
                                       auth_fn,
Packit Service 31306d
                                       auth_data,
Packit Service 31306d
                                       pkey);
Packit Service 31306d
Packit Service 31306d
    SAFE_FREE(key_buf);
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Export a private key to a pem file on disk, or OpenSSH format for
Packit Service 31306d
 *        keytype ssh-ed25519
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  privkey  The private key to export.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  passphrase The passphrase to use to encrypt the key with or
Packit Service 31306d
 *             NULL. An empty string means no passphrase.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  auth_fn  An auth function you may want to use or NULL.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  auth_data Private data passed to the auth function.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  filename  The path where to store the pem file.
Packit Service 31306d
 *
Packit Service 31306d
 * @return     SSH_OK on success, SSH_ERROR on error.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_export_privkey_file(const ssh_key privkey,
Packit Service 31306d
                                const char *passphrase,
Packit Service 31306d
                                ssh_auth_callback auth_fn,
Packit Service 31306d
                                void *auth_data,
Packit Service 31306d
                                const char *filename)
Packit Service 31306d
{
Packit Service 31306d
    ssh_string blob;
Packit Service 31306d
    FILE *fp;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (privkey == NULL || !ssh_key_is_private(privkey)) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    fp = fopen(filename, "wb");
Packit Service 31306d
    if (fp == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_FUNCTIONS, "Error opening %s: %s",
Packit Service 31306d
                filename, strerror(errno));
Packit Service 31306d
        return SSH_EOF;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (privkey->type == SSH_KEYTYPE_ED25519){
Packit Service 31306d
        blob = ssh_pki_openssh_privkey_export(privkey,
Packit Service 31306d
                                              passphrase,
Packit Service 31306d
                                              auth_fn,
Packit Service 31306d
                                              auth_data);
Packit Service 31306d
    } else {
Packit Service 31306d
        blob = pki_private_key_to_pem(privkey,
Packit Service 31306d
                                      passphrase,
Packit Service 31306d
                                      auth_fn,
Packit Service 31306d
                                      auth_data);
Packit Service 31306d
    }
Packit Service 31306d
    if (blob == NULL) {
Packit Service 31306d
        fclose(fp);
Packit Service 31306d
        return -1;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = fwrite(ssh_string_data(blob), ssh_string_len(blob), 1, fp);
Packit Service 31306d
    SSH_STRING_FREE(blob);
Packit Service 31306d
    if (rc != 1 || ferror(fp)) {
Packit Service 31306d
        fclose(fp);
Packit Service 31306d
        unlink(filename);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    fclose(fp);
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/* temporary function to migrate seemlessly to ssh_key */
Packit Service 31306d
ssh_public_key ssh_pki_convert_key_to_publickey(const ssh_key key) {
Packit Service 31306d
    ssh_public_key pub;
Packit Service 31306d
    ssh_key tmp;
Packit Service 31306d
Packit Service 31306d
    if(key == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    tmp = ssh_key_dup(key);
Packit Service 31306d
    if (tmp == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    pub = malloc(sizeof(struct ssh_public_key_struct));
Packit Service 31306d
    if (pub == NULL) {
Packit Service 31306d
        ssh_key_free(tmp);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
    ZERO_STRUCTP(pub);
Packit Service 31306d
Packit Service 31306d
    pub->type = tmp->type;
Packit Service 31306d
    pub->type_c = tmp->type_c;
Packit Service 31306d
Packit Service 31306d
    pub->dsa_pub = tmp->dsa;
Packit Service 31306d
    tmp->dsa = NULL;
Packit Service 31306d
    pub->rsa_pub = tmp->rsa;
Packit Service 31306d
    tmp->rsa = NULL;
Packit Service 31306d
Packit Service 31306d
    ssh_key_free(tmp);
Packit Service 31306d
Packit Service 31306d
    return pub;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
ssh_private_key ssh_pki_convert_key_to_privatekey(const ssh_key key) {
Packit Service 31306d
    ssh_private_key privkey;
Packit Service 31306d
Packit Service 31306d
    privkey = malloc(sizeof(struct ssh_private_key_struct));
Packit Service 31306d
    if (privkey == NULL) {
Packit Service 31306d
        ssh_key_free(key);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    privkey->type = key->type;
Packit Service 31306d
    privkey->dsa_priv = key->dsa;
Packit Service 31306d
    privkey->rsa_priv = key->rsa;
Packit Service 31306d
Packit Service 31306d
    return privkey;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int pki_import_privkey_buffer(enum ssh_keytypes_e type,
Packit Service 31306d
                              ssh_buffer buffer,
Packit Service 31306d
                              ssh_key *pkey)
Packit Service 31306d
{
Packit Service 31306d
    ssh_key key = NULL;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    key = ssh_key_new();
Packit Service 31306d
    if (key == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    key->type = type;
Packit Service 31306d
    key->type_c = ssh_key_type_to_char(type);
Packit Service 31306d
    key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
Packit Service 31306d
Packit Service 31306d
    switch (type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            {
Packit Service 31306d
                ssh_string p = NULL;
Packit Service 31306d
                ssh_string q = NULL;
Packit Service 31306d
                ssh_string g = NULL;
Packit Service 31306d
                ssh_string pubkey = NULL;
Packit Service 31306d
                ssh_string privkey = NULL;
Packit Service 31306d
Packit Service 31306d
                rc = ssh_buffer_unpack(buffer, "SSSSS", &p, &q, &g,
Packit Service 31306d
                                       &pubkey, &privkey);
Packit Service 31306d
                if (rc != SSH_OK) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Unpack error");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                rc = pki_privkey_build_dss(key, p, q, g, pubkey, privkey);
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
                ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
Packit Service 31306d
                ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
Packit Service 31306d
                ssh_log_hexdump("g", ssh_string_data(g), ssh_string_len(g));
Packit Service 31306d
                ssh_log_hexdump("pubkey", ssh_string_data(pubkey),
Packit Service 31306d
                               ssh_string_len(pubkey));
Packit Service 31306d
                ssh_log_hexdump("privkey", ssh_string_data(privkey),
Packit Service 31306d
                               ssh_string_len(privkey));
Packit Service 31306d
#endif
Packit Service 31306d
                ssh_string_burn(p);
Packit Service 31306d
                SSH_STRING_FREE(p);
Packit Service 31306d
                ssh_string_burn(q);
Packit Service 31306d
                SSH_STRING_FREE(q);
Packit Service 31306d
                ssh_string_burn(g);
Packit Service 31306d
                SSH_STRING_FREE(g);
Packit Service 31306d
                ssh_string_burn(pubkey);
Packit Service 31306d
                SSH_STRING_FREE(pubkey);
Packit Service 31306d
                ssh_string_burn(privkey);
Packit Service 31306d
                SSH_STRING_FREE(privkey);
Packit Service 31306d
                if (rc == SSH_ERROR) {
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            {
Packit Service 31306d
                ssh_string n = NULL;
Packit Service 31306d
                ssh_string e = NULL;
Packit Service 31306d
                ssh_string d = NULL;
Packit Service 31306d
                ssh_string iqmp = NULL;
Packit Service 31306d
                ssh_string p = NULL;
Packit Service 31306d
                ssh_string q = NULL;
Packit Service 31306d
Packit Service 31306d
                rc = ssh_buffer_unpack(buffer, "SSSSSS", &n, &e, &d,
Packit Service 31306d
                                       &iqmp, &p, &q);
Packit Service 31306d
                if (rc != SSH_OK) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Unpack error");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                rc = pki_privkey_build_rsa(key, n, e, d, iqmp, p, q);
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
                ssh_log_hexdump("n", ssh_string_data(n), ssh_string_len(n));
Packit Service 31306d
                ssh_log_hexdump("e", ssh_string_data(e), ssh_string_len(e));
Packit Service 31306d
                ssh_log_hexdump("d", ssh_string_data(d), ssh_string_len(d));
Packit Service 31306d
                ssh_log_hexdump("iqmp", ssh_string_data(iqmp),
Packit Service 31306d
                               ssh_string_len(iqmp));
Packit Service 31306d
                ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
Packit Service 31306d
                ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
Packit Service 31306d
#endif
Packit Service 31306d
                ssh_string_burn(n);
Packit Service 31306d
                SSH_STRING_FREE(n);
Packit Service 31306d
                ssh_string_burn(e);
Packit Service 31306d
                SSH_STRING_FREE(e);
Packit Service 31306d
                ssh_string_burn(d);
Packit Service 31306d
                SSH_STRING_FREE(d);
Packit Service 31306d
                ssh_string_burn(iqmp);
Packit Service 31306d
                SSH_STRING_FREE(iqmp);
Packit Service 31306d
                ssh_string_burn(p);
Packit Service 31306d
                SSH_STRING_FREE(p);
Packit Service 31306d
                ssh_string_burn(q);
Packit Service 31306d
                SSH_STRING_FREE(q);
Packit Service 31306d
                if (rc == SSH_ERROR) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Failed to build RSA private key");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#ifdef HAVE_ECC
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
            {
Packit Service 31306d
                ssh_string e = NULL;
Packit Service 31306d
                ssh_string exp = NULL;
Packit Service 31306d
                ssh_string i = NULL;
Packit Service 31306d
                int nid;
Packit Service 31306d
Packit Service 31306d
                rc = ssh_buffer_unpack(buffer, "SSS", &i, &e, &exp);
Packit Service 31306d
                if (rc != SSH_OK) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Unpack error");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i));
Packit Service 31306d
                SSH_STRING_FREE(i);
Packit Service 31306d
                if (nid == -1) {
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                rc = pki_privkey_build_ecdsa(key, nid, e, exp);
Packit Service 31306d
                ssh_string_burn(e);
Packit Service 31306d
                SSH_STRING_FREE(e);
Packit Service 31306d
                ssh_string_burn(exp);
Packit Service 31306d
                SSH_STRING_FREE(exp);
Packit Service 31306d
                if (rc < 0) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Failed to build ECDSA private key");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
            {
Packit Service 31306d
                ssh_string pubkey = NULL, privkey = NULL;
Packit Service 31306d
Packit Service 31306d
                rc = ssh_buffer_unpack(buffer, "SS", &pubkey, &privkey);
Packit Service 31306d
                if (rc != SSH_OK){
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Unpack error");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                rc = pki_privkey_build_ed25519(key, pubkey, privkey);
Packit Service 31306d
                ssh_string_burn(privkey);
Packit Service 31306d
                SSH_STRING_FREE(privkey);
Packit Service 31306d
                SSH_STRING_FREE(pubkey);
Packit Service 31306d
                if (rc != SSH_OK) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Failed to build ed25519 key");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        default:
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARN, "Unknown private key type (%d)", type);
Packit Service 31306d
            goto fail;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    *pkey = key;
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
fail:
Packit Service 31306d
    ssh_key_free(key);
Packit Service 31306d
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int pki_import_pubkey_buffer(ssh_buffer buffer,
Packit Service 31306d
                                    enum ssh_keytypes_e type,
Packit Service 31306d
                                    ssh_key *pkey) {
Packit Service 31306d
    ssh_key key = NULL;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    key = ssh_key_new();
Packit Service 31306d
    if (key == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    key->type = type;
Packit Service 31306d
    key->type_c = ssh_key_type_to_char(type);
Packit Service 31306d
    key->flags = SSH_KEY_FLAG_PUBLIC;
Packit Service 31306d
Packit Service 31306d
    switch (type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            {
Packit Service 31306d
                ssh_string p = NULL;
Packit Service 31306d
                ssh_string q = NULL;
Packit Service 31306d
                ssh_string g = NULL;
Packit Service 31306d
                ssh_string pubkey = NULL;
Packit Service 31306d
Packit Service 31306d
                rc = ssh_buffer_unpack(buffer, "SSSS", &p, &q, &g, &pubkey);
Packit Service 31306d
                if (rc != SSH_OK) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Unpack error");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                rc = pki_pubkey_build_dss(key, p, q, g, pubkey);
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
                ssh_log_hexdump("p", ssh_string_data(p), ssh_string_len(p));
Packit Service 31306d
                ssh_log_hexdump("q", ssh_string_data(q), ssh_string_len(q));
Packit Service 31306d
                ssh_log_hexdump("g", ssh_string_data(g), ssh_string_len(g));
Packit Service 31306d
#endif
Packit Service 31306d
                ssh_string_burn(p);
Packit Service 31306d
                SSH_STRING_FREE(p);
Packit Service 31306d
                ssh_string_burn(q);
Packit Service 31306d
                SSH_STRING_FREE(q);
Packit Service 31306d
                ssh_string_burn(g);
Packit Service 31306d
                SSH_STRING_FREE(g);
Packit Service 31306d
                ssh_string_burn(pubkey);
Packit Service 31306d
                SSH_STRING_FREE(pubkey);
Packit Service 31306d
                if (rc == SSH_ERROR) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Failed to build DSA public key");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            {
Packit Service 31306d
                ssh_string e = NULL;
Packit Service 31306d
                ssh_string n = NULL;
Packit Service 31306d
Packit Service 31306d
                rc = ssh_buffer_unpack(buffer, "SS", &e, &n);
Packit Service 31306d
                if (rc != SSH_OK) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Unpack error");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                rc = pki_pubkey_build_rsa(key, e, n);
Packit Service 31306d
#ifdef DEBUG_CRYPTO
Packit Service 31306d
                ssh_log_hexdump("e", ssh_string_data(e), ssh_string_len(e));
Packit Service 31306d
                ssh_log_hexdump("n", ssh_string_data(n), ssh_string_len(n));
Packit Service 31306d
#endif
Packit Service 31306d
                ssh_string_burn(e);
Packit Service 31306d
                SSH_STRING_FREE(e);
Packit Service 31306d
                ssh_string_burn(n);
Packit Service 31306d
                SSH_STRING_FREE(n);
Packit Service 31306d
                if (rc == SSH_ERROR) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Failed to build RSA public key");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#ifdef HAVE_ECC
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA: /* deprecated */
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
            {
Packit Service 31306d
                ssh_string e = NULL;
Packit Service 31306d
                ssh_string i = NULL;
Packit Service 31306d
                int nid;
Packit Service 31306d
Packit Service 31306d
                rc = ssh_buffer_unpack(buffer, "SS", &i, &e);
Packit Service 31306d
                if (rc != SSH_OK) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Unpack error");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                nid = pki_key_ecdsa_nid_from_name(ssh_string_get_char(i));
Packit Service 31306d
                SSH_STRING_FREE(i);
Packit Service 31306d
                if (nid == -1) {
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                rc = pki_pubkey_build_ecdsa(key, nid, e);
Packit Service 31306d
                ssh_string_burn(e);
Packit Service 31306d
                SSH_STRING_FREE(e);
Packit Service 31306d
                if (rc < 0) {
Packit Service 31306d
                    SSH_LOG(SSH_LOG_WARN, "Failed to build ECDSA public key");
Packit Service 31306d
                    goto fail;
Packit Service 31306d
                }
Packit Service 31306d
Packit Service 31306d
                /* Update key type */
Packit Service 31306d
                if (type == SSH_KEYTYPE_ECDSA) {
Packit Service 31306d
                    key->type_c = ssh_pki_key_ecdsa_name(key);
Packit Service 31306d
                }
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
        {
Packit Service 31306d
            ssh_string pubkey = ssh_buffer_get_ssh_string(buffer);
Packit Service 31306d
            if (ssh_string_len(pubkey) != ED25519_KEY_LEN) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "Invalid public key length");
Packit Service 31306d
                ssh_string_burn(pubkey);
Packit Service 31306d
                SSH_STRING_FREE(pubkey);
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
Packit Service 31306d
            if (key->ed25519_pubkey == NULL) {
Packit Service 31306d
                ssh_string_burn(pubkey);
Packit Service 31306d
                SSH_STRING_FREE(pubkey);
Packit Service 31306d
                goto fail;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_KEY_LEN);
Packit Service 31306d
            ssh_string_burn(pubkey);
Packit Service 31306d
            SSH_STRING_FREE(pubkey);
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
        case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        default:
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARN, "Unknown public key protocol %d", type);
Packit Service 31306d
            goto fail;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    *pkey = key;
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
fail:
Packit Service 31306d
    ssh_key_free(key);
Packit Service 31306d
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
static int pki_import_cert_buffer(ssh_buffer buffer,
Packit Service 31306d
                                  enum ssh_keytypes_e type,
Packit Service 31306d
                                  ssh_key *pkey) {
Packit Service 31306d
    ssh_buffer cert;
Packit Service 31306d
    ssh_string tmp_s;
Packit Service 31306d
    const char *type_c;
Packit Service 31306d
    ssh_key key = NULL;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    /*
Packit Service 31306d
     * The cert blob starts with the key type as an ssh_string, but this
Packit Service 31306d
     * string has been read out of the buffer to identify the key type.
Packit Service 31306d
     * Simply add it again as first element before copying the rest.
Packit Service 31306d
     */
Packit Service 31306d
    cert = ssh_buffer_new();
Packit Service 31306d
    if (cert == NULL) {
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
    type_c = ssh_key_type_to_char(type);
Packit Service 31306d
    tmp_s = ssh_string_from_char(type_c);
Packit Service 31306d
    if (tmp_s == NULL) {
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
    rc = ssh_buffer_add_ssh_string(cert, tmp_s);
Packit Service 31306d
    SSH_STRING_FREE(tmp_s);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
    rc = ssh_buffer_add_buffer(cert, buffer);
Packit Service 31306d
    if (rc != 0) {
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /*
Packit Service 31306d
     * After the key type, comes an ssh_string nonce. Just after this comes the
Packit Service 31306d
     * cert public key, which can be parsed out of the buffer.
Packit Service 31306d
     */
Packit Service 31306d
    tmp_s = ssh_buffer_get_ssh_string(buffer);
Packit Service 31306d
    if (tmp_s == NULL) {
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
    SSH_STRING_FREE(tmp_s);
Packit Service 31306d
Packit Service 31306d
    switch (type) {
Packit Service 31306d
        case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_DSS, &key);
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_RSA, &key);
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_ECDSA_P256, &key);
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_ECDSA_P384, &key);
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_ECDSA_P521, &key);
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
            rc = pki_import_pubkey_buffer(buffer, SSH_KEYTYPE_ED25519, &key);
Packit Service 31306d
            break;
Packit Service 31306d
        default:
Packit Service 31306d
            key = ssh_key_new();
Packit Service 31306d
    }
Packit Service 31306d
    if (rc != 0 || key == NULL) {
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    key->type = type;
Packit Service 31306d
    key->type_c = type_c;
Packit Service 31306d
    key->cert = (void*) cert;
Packit Service 31306d
Packit Service 31306d
    *pkey = key;
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
Packit Service 31306d
fail:
Packit Service 31306d
    ssh_key_free(key);
Packit Service 31306d
    SSH_BUFFER_FREE(cert);
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Import a base64 formated public key from a memory c-string.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  b64_key  The base64 key to format.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  type     The type of the key to format.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] pkey     A pointer where the allocated key can be stored. You
Packit Service 31306d
 *                      need to free the memory.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              SSH_OK on success, SSH_ERROR on error.
Packit Service 31306d
 *
Packit Service 31306d
 * @see ssh_key_free()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_import_pubkey_base64(const char *b64_key,
Packit Service 31306d
                                 enum ssh_keytypes_e type,
Packit Service 31306d
                                 ssh_key *pkey) {
Packit Service 31306d
    ssh_buffer buffer = NULL;
Packit Service 31306d
    ssh_string type_s = NULL;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (b64_key == NULL || pkey == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    buffer = base64_to_bin(b64_key);
Packit Service 31306d
    if (buffer == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    type_s = ssh_buffer_get_ssh_string(buffer);
Packit Service 31306d
    if (type_s == NULL) {
Packit Service 31306d
        SSH_BUFFER_FREE(buffer);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    SSH_STRING_FREE(type_s);
Packit Service 31306d
Packit Service 31306d
    if (is_cert_type(type)) {
Packit Service 31306d
        rc = pki_import_cert_buffer(buffer, type, pkey);
Packit Service 31306d
    } else {
Packit Service 31306d
        rc = pki_import_pubkey_buffer(buffer, type, pkey);
Packit Service 31306d
    }
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Import a public key from a ssh string.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  key_blob The key blob to import as specified in RFC 4253 section
Packit Service 31306d
 *                      6.6 "Public Key Algorithms".
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] pkey     A pointer where the allocated key can be stored. You
Packit Service 31306d
 *                      need to free the memory.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              SSH_OK on success, SSH_ERROR on error.
Packit Service 31306d
 *
Packit Service 31306d
 * @see ssh_key_free()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_import_pubkey_blob(const ssh_string key_blob,
Packit Service 31306d
                               ssh_key *pkey) {
Packit Service 31306d
    ssh_buffer buffer = NULL;
Packit Service 31306d
    ssh_string type_s = NULL;
Packit Service 31306d
    enum ssh_keytypes_e type;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (key_blob == NULL || pkey == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    buffer = ssh_buffer_new();
Packit Service 31306d
    if (buffer == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Out of memory!");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_add_data(buffer, ssh_string_data(key_blob),
Packit Service 31306d
            ssh_string_len(key_blob));
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Out of memory!");
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    type_s = ssh_buffer_get_ssh_string(buffer);
Packit Service 31306d
    if (type_s == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Out of memory!");
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    type = ssh_key_type_from_name(ssh_string_get_char(type_s));
Packit Service 31306d
    if (type == SSH_KEYTYPE_UNKNOWN) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Unknown key type found!");
Packit Service 31306d
        goto fail;
Packit Service 31306d
    }
Packit Service 31306d
    SSH_STRING_FREE(type_s);
Packit Service 31306d
Packit Service 31306d
    if (is_cert_type(type)) {
Packit Service 31306d
        rc = pki_import_cert_buffer(buffer, type, pkey);
Packit Service 31306d
    } else {
Packit Service 31306d
        rc = pki_import_pubkey_buffer(buffer, type, pkey);
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
fail:
Packit Service 31306d
    SSH_BUFFER_FREE(buffer);
Packit Service 31306d
    SSH_STRING_FREE(type_s);
Packit Service 31306d
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Import a public key from the given filename.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  filename The path to the public key.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] pkey     A pointer to store the allocated public key. You need to
Packit Service 31306d
 *                      free the memory.
Packit Service 31306d
 *
Packit Service 31306d
 * @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
Packit Service 31306d
 *          denied, SSH_ERROR otherwise.
Packit Service 31306d
 *
Packit Service 31306d
 * @see ssh_key_free()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_import_pubkey_file(const char *filename, ssh_key *pkey)
Packit Service 31306d
{
Packit Service 31306d
    enum ssh_keytypes_e type;
Packit Service 31306d
    struct stat sb;
Packit Service 31306d
    char *key_buf, *p;
Packit Service 31306d
    size_t buflen, i;
Packit Service 31306d
    const char *q;
Packit Service 31306d
    FILE *file;
Packit Service 31306d
    off_t size;
Packit Service 31306d
    int rc, cmp;
Packit Service 31306d
Packit Service 31306d
    if (pkey == NULL || filename == NULL || *filename == '\0') {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    file = fopen(filename, "rb");
Packit Service 31306d
    if (file == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Error opening %s: %s",
Packit Service 31306d
                    filename, strerror(errno));
Packit Service 31306d
        return SSH_EOF;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = fstat(fileno(file), &sb);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        fclose(file);
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Error gettint stat of %s: %s",
Packit Service 31306d
                    filename, strerror(errno));
Packit Service 31306d
        switch (errno) {
Packit Service 31306d
            case ENOENT:
Packit Service 31306d
            case EACCES:
Packit Service 31306d
                return SSH_EOF;
Packit Service 31306d
        }
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (sb.st_size > MAX_PUBKEY_SIZE) {
Packit Service 31306d
        fclose(file);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    key_buf = malloc(sb.st_size + 1);
Packit Service 31306d
    if (key_buf == NULL) {
Packit Service 31306d
        fclose(file);
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Out of memory!");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    size = fread(key_buf, 1, sb.st_size, file);
Packit Service 31306d
    fclose(file);
Packit Service 31306d
Packit Service 31306d
    if (size != sb.st_size) {
Packit Service 31306d
        SAFE_FREE(key_buf);
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Error reading %s: %s",
Packit Service 31306d
                    filename, strerror(errno));
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    key_buf[size] = '\0';
Packit Service 31306d
    buflen = strlen(key_buf);
Packit Service 31306d
Packit Service 31306d
    /* Test for new OpenSSH key format first */
Packit Service 31306d
    cmp = strncmp(key_buf, OPENSSH_HEADER_BEGIN, strlen(OPENSSH_HEADER_BEGIN));
Packit Service 31306d
    if (cmp == 0) {
Packit Service 31306d
        *pkey = ssh_pki_openssh_pubkey_import(key_buf);
Packit Service 31306d
        SAFE_FREE(key_buf);
Packit Service 31306d
        if (*pkey == NULL) {
Packit Service 31306d
            SSH_LOG(SSH_LOG_WARN, "Failed to import public key from OpenSSH"
Packit Service 31306d
                                  " private key file");
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
        return SSH_OK;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* This the old one-line public key format */
Packit Service 31306d
    q = p = key_buf;
Packit Service 31306d
    for (i = 0; i < buflen; i++) {
Packit Service 31306d
        if (isspace((int)p[i])) {
Packit Service 31306d
            p[i] = '\0';
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    type = ssh_key_type_from_name(q);
Packit Service 31306d
    if (type == SSH_KEYTYPE_UNKNOWN) {
Packit Service 31306d
        SAFE_FREE(key_buf);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    q = &p[i + 1];
Packit Service 31306d
    for (; i < buflen; i++) {
Packit Service 31306d
        if (isspace((int)p[i])) {
Packit Service 31306d
            p[i] = '\0';
Packit Service 31306d
            break;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_pki_import_pubkey_base64(q, type, pkey);
Packit Service 31306d
    SAFE_FREE(key_buf);
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Import a base64 formated certificate from a memory c-string.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  b64_cert  The base64 cert to format.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  type     The type of the cert to format.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] pkey     A pointer where the allocated key can be stored. You
Packit Service 31306d
 *                      need to free the memory.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              SSH_OK on success, SSH_ERROR on error.
Packit Service 31306d
 *
Packit Service 31306d
 * @see ssh_key_free()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_import_cert_base64(const char *b64_cert,
Packit Service 31306d
                               enum ssh_keytypes_e type,
Packit Service 31306d
                               ssh_key *pkey) {
Packit Service 31306d
    return ssh_pki_import_pubkey_base64(b64_cert, type, pkey);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Import a certificate from a ssh string.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  cert_blob The cert blob to import as specified in RFC 4253 section
Packit Service 31306d
 *                      6.6 "Public Key Algorithms".
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] pkey     A pointer where the allocated key can be stored. You
Packit Service 31306d
 *                      need to free the memory.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              SSH_OK on success, SSH_ERROR on error.
Packit Service 31306d
 *
Packit Service 31306d
 * @see ssh_key_free()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_import_cert_blob(const ssh_string cert_blob,
Packit Service 31306d
                             ssh_key *pkey) {
Packit Service 31306d
    return ssh_pki_import_pubkey_blob(cert_blob, pkey);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Import a certificate from the given filename.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  filename The path to the certificate.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] pkey     A pointer to store the allocated certificate. You need to
Packit Service 31306d
 *                      free the memory.
Packit Service 31306d
 *
Packit Service 31306d
 * @returns SSH_OK on success, SSH_EOF if the file doesn't exist or permission
Packit Service 31306d
 *          denied, SSH_ERROR otherwise.
Packit Service 31306d
 *
Packit Service 31306d
 * @see ssh_key_free()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_import_cert_file(const char *filename, ssh_key *pkey)
Packit Service 31306d
{
Packit Service 31306d
    return ssh_pki_import_pubkey_file(filename, pkey);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Generates a keypair.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] type      Type of key to create
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] parameter Parameter to the creation of key:
Packit Service 31306d
 *                      rsa : length of the key in bits (e.g. 1024, 2048, 4096)
Packit Service 31306d
 *                      dsa : length of the key in bits (e.g. 1024, 2048, 3072)
Packit Service 31306d
 * @param[out] pkey     A pointer to store the allocated private key. You need
Packit Service 31306d
 *                      to free the memory.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              SSH_OK on success, SSH_ERROR on error.
Packit Service 31306d
 *
Packit Service 31306d
 * @warning             Generating a key pair may take some time.
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
Packit Service 31306d
        ssh_key *pkey){
Packit Service 31306d
    int rc;
Packit Service 31306d
    ssh_key key = ssh_key_new();
Packit Service 31306d
Packit Service 31306d
    if (key == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    key->type = type;
Packit Service 31306d
    key->type_c = ssh_key_type_to_char(type);
Packit Service 31306d
    key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
Packit Service 31306d
Packit Service 31306d
    switch(type){
Packit Service 31306d
        case SSH_KEYTYPE_RSA:
Packit Service 31306d
            rc = pki_key_generate_rsa(key, parameter);
Packit Service 31306d
            if(rc == SSH_ERROR)
Packit Service 31306d
                goto error;
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_DSS:
Packit Service 31306d
            rc = pki_key_generate_dss(key, parameter);
Packit Service 31306d
            if(rc == SSH_ERROR)
Packit Service 31306d
                goto error;
Packit Service 31306d
            break;
Packit Service 31306d
#ifdef HAVE_ECC
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA: /* deprecated */
Packit Service 31306d
            rc = pki_key_generate_ecdsa(key, parameter);
Packit Service 31306d
            if (rc == SSH_ERROR) {
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
Packit Service 31306d
            /* Update key type */
Packit Service 31306d
            key->type_c = ssh_pki_key_ecdsa_name(key);
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
            rc = pki_key_generate_ecdsa(key, 256);
Packit Service 31306d
            if (rc == SSH_ERROR) {
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
            rc = pki_key_generate_ecdsa(key, 384);
Packit Service 31306d
            if (rc == SSH_ERROR) {
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
            rc = pki_key_generate_ecdsa(key, 521);
Packit Service 31306d
            if (rc == SSH_ERROR) {
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
#endif
Packit Service 31306d
        case SSH_KEYTYPE_ED25519:
Packit Service 31306d
            rc = pki_key_generate_ed25519(key);
Packit Service 31306d
            if (rc == SSH_ERROR) {
Packit Service 31306d
                goto error;
Packit Service 31306d
            }
Packit Service 31306d
            break;
Packit Service 31306d
        case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
        case SSH_KEYTYPE_RSA1:
Packit Service 31306d
        case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        default:
Packit Service 31306d
            goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    *pkey = key;
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
error:
Packit Service 31306d
    ssh_key_free(key);
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Create a public key from a private key.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  privkey  The private key to get the public key from.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] pkey     A pointer to store the newly allocated public key. You
Packit Service 31306d
 *                      NEED to free the key.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              SSH_OK on success, SSH_ERROR on error.
Packit Service 31306d
 *
Packit Service 31306d
 * @see ssh_key_free()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_export_privkey_to_pubkey(const ssh_key privkey,
Packit Service 31306d
                                     ssh_key *pkey)
Packit Service 31306d
{
Packit Service 31306d
    ssh_key pubkey;
Packit Service 31306d
Packit Service 31306d
    if (privkey == NULL || !ssh_key_is_private(privkey)) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    pubkey = pki_key_dup(privkey, 1);
Packit Service 31306d
    if (pubkey == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    *pkey = pubkey;
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Create a key_blob from a public key.
Packit Service 31306d
 *
Packit Service 31306d
 * The "key_blob" is encoded as per RFC 4253 section 6.6 "Public Key
Packit Service 31306d
 * Algorithms" for any of the supported protocol 2 key types.
Packit Service 31306d
 * Encoding of EC keys is described in RFC 5656 section 3.1 "Key
Packit Service 31306d
 * Format".
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  key      A public or private key to create the public ssh_string
Packit Service 31306d
 *                      from.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] pblob    A pointer to store the newly allocated key blob. You
Packit Service 31306d
 *                      NEED to free it.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              SSH_OK on success, SSH_ERROR otherwise.
Packit Service 31306d
 *
Packit Service 31306d
 * @see SSH_STRING_FREE()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_export_pubkey_blob(const ssh_key key,
Packit Service 31306d
                               ssh_string *pblob)
Packit Service 31306d
{
Packit Service 31306d
    ssh_string blob;
Packit Service 31306d
Packit Service 31306d
    if (key == NULL) {
Packit Service 31306d
        return SSH_OK;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    blob = pki_publickey_to_blob(key);
Packit Service 31306d
    if (blob == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    *pblob = blob;
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Convert a public key to a base64 encoded key.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] key       The key to hash
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] b64_key  A pointer to store the allocated base64 encoded key. You
Packit Service 31306d
 *                      need to free the buffer.
Packit Service 31306d
 *
Packit Service 31306d
 * @return              SSH_OK on success, SSH_ERROR on error.
Packit Service 31306d
 *
Packit Service 31306d
 * @see SSH_STRING_FREE_CHAR()
Packit Service 31306d
 */
Packit Service 31306d
int ssh_pki_export_pubkey_base64(const ssh_key key,
Packit Service 31306d
                                 char **b64_key)
Packit Service 31306d
{
Packit Service 31306d
    ssh_string key_blob;
Packit Service 31306d
    unsigned char *b64;
Packit Service 31306d
Packit Service 31306d
    if (key == NULL || b64_key == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    key_blob = pki_publickey_to_blob(key);
Packit Service 31306d
    if (key_blob == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    b64 = bin_to_base64(ssh_string_data(key_blob), ssh_string_len(key_blob));
Packit Service 31306d
    SSH_STRING_FREE(key_blob);
Packit Service 31306d
    if (b64 == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    *b64_key = (char *)b64;
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int ssh_pki_export_pubkey_file(const ssh_key key,
Packit Service 31306d
                               const char *filename)
Packit Service 31306d
{
Packit Service 31306d
    char key_buf[4096];
Packit Service 31306d
    char host[256];
Packit Service 31306d
    char *b64_key;
Packit Service 31306d
    char *user;
Packit Service 31306d
    FILE *fp;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (key == NULL || filename == NULL || *filename == '\0') {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    user = ssh_get_local_username();
Packit Service 31306d
    if (user == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = gethostname(host, sizeof(host));
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        free(user);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_pki_export_pubkey_base64(key, &b64_key);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        free(user);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = snprintf(key_buf, sizeof(key_buf),
Packit Service 31306d
                  "%s %s %s@%s\n",
Packit Service 31306d
                  key->type_c,
Packit Service 31306d
                  b64_key,
Packit Service 31306d
                  user,
Packit Service 31306d
                  host);
Packit Service 31306d
    free(user);
Packit Service 31306d
    free(b64_key);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    fp = fopen(filename, "wb+");
Packit Service 31306d
    if (fp == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    rc = fwrite(key_buf, strlen(key_buf), 1, fp);
Packit Service 31306d
    if (rc != 1 || ferror(fp)) {
Packit Service 31306d
        fclose(fp);
Packit Service 31306d
        unlink(filename);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    fclose(fp);
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @brief Copy the certificate part of a public key into a private key.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  certkey  The certificate key.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]  privkey  The target private key to copy the certificate to.
Packit Service 31306d
 *
Packit Service 31306d
 * @returns SSH_OK on success, SSH_ERROR otherwise.
Packit Service 31306d
 **/
Packit Service 31306d
int ssh_pki_copy_cert_to_privkey(const ssh_key certkey, ssh_key privkey) {
Packit Service 31306d
  ssh_buffer cert_buffer;
Packit Service 31306d
  int rc;
Packit Service 31306d
Packit Service 31306d
  if (certkey == NULL || privkey == NULL) {
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (privkey->cert != NULL) {
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  if (certkey->cert == NULL) {
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  cert_buffer = ssh_buffer_new();
Packit Service 31306d
  if (cert_buffer == NULL) {
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  rc = ssh_buffer_add_buffer(cert_buffer, certkey->cert);
Packit Service 31306d
  if (rc != 0) {
Packit Service 31306d
      SSH_BUFFER_FREE(cert_buffer);
Packit Service 31306d
      return SSH_ERROR;
Packit Service 31306d
  }
Packit Service 31306d
Packit Service 31306d
  privkey->cert = cert_buffer;
Packit Service 31306d
  privkey->cert_type = certkey->type;
Packit Service 31306d
  return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int ssh_pki_export_signature_blob(const ssh_signature sig,
Packit Service 31306d
                                  ssh_string *sig_blob)
Packit Service 31306d
{
Packit Service 31306d
    ssh_buffer buf = NULL;
Packit Service 31306d
    ssh_string str;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (sig == NULL || sig_blob == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    buf = ssh_buffer_new();
Packit Service 31306d
    if (buf == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    str = ssh_string_from_char(sig->type_c);
Packit Service 31306d
    if (str == NULL) {
Packit Service 31306d
        SSH_BUFFER_FREE(buf);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_add_ssh_string(buf, str);
Packit Service 31306d
    SSH_STRING_FREE(str);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        SSH_BUFFER_FREE(buf);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    str = pki_signature_to_blob(sig);
Packit Service 31306d
    if (str == NULL) {
Packit Service 31306d
        SSH_BUFFER_FREE(buf);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_add_ssh_string(buf, str);
Packit Service 31306d
    SSH_STRING_FREE(str);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        SSH_BUFFER_FREE(buf);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    str = ssh_string_new(ssh_buffer_get_len(buf));
Packit Service 31306d
    if (str == NULL) {
Packit Service 31306d
        SSH_BUFFER_FREE(buf);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    ssh_string_fill(str, ssh_buffer_get(buf), ssh_buffer_get_len(buf));
Packit Service 31306d
    SSH_BUFFER_FREE(buf);
Packit Service 31306d
Packit Service 31306d
    *sig_blob = str;
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int ssh_pki_import_signature_blob(const ssh_string sig_blob,
Packit Service 31306d
                                  const ssh_key pubkey,
Packit Service 31306d
                                  ssh_signature *psig)
Packit Service 31306d
{
Packit Service 31306d
    ssh_signature sig = NULL;
Packit Service 31306d
    enum ssh_keytypes_e type;
Packit Service 31306d
    enum ssh_digest_e hash_type;
Packit Service 31306d
    ssh_string algorithm = NULL, blob = NULL;
Packit Service 31306d
    ssh_buffer buf;
Packit Service 31306d
    const char *alg = NULL;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (sig_blob == NULL || psig == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    buf = ssh_buffer_new();
Packit Service 31306d
    if (buf == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_add_data(buf,
Packit Service 31306d
                             ssh_string_data(sig_blob),
Packit Service 31306d
                             ssh_string_len(sig_blob));
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        SSH_BUFFER_FREE(buf);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    algorithm = ssh_buffer_get_ssh_string(buf);
Packit Service 31306d
    if (algorithm == NULL) {
Packit Service 31306d
        SSH_BUFFER_FREE(buf);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    alg = ssh_string_get_char(algorithm);
Packit Service 31306d
    type = ssh_key_type_from_signature_name(alg);
Packit Service 31306d
    hash_type = ssh_key_hash_from_name(alg);
Packit Service 31306d
    SSH_STRING_FREE(algorithm);
Packit Service 31306d
Packit Service 31306d
    blob = ssh_buffer_get_ssh_string(buf);
Packit Service 31306d
    SSH_BUFFER_FREE(buf);
Packit Service 31306d
    if (blob == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    sig = pki_signature_from_blob(pubkey, blob, type, hash_type);
Packit Service 31306d
    SSH_STRING_FREE(blob);
Packit Service 31306d
    if (sig == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    *psig = sig;
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Check if the provided key can be used with the provided hash type for
Packit Service 31306d
 * data signing or signature verification.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in]   key         The key to be checked.
Packit Service 31306d
 * @param[in]   hash_type   The digest algorithm to be checked.
Packit Service 31306d
 *
Packit Service 31306d
 * @return  SSH_OK if compatible; SSH_ERROR otherwise
Packit Service 31306d
 */
Packit Service 31306d
int pki_key_check_hash_compatible(ssh_key key,
Packit Service 31306d
                                  enum ssh_digest_e hash_type)
Packit Service 31306d
{
Packit Service 31306d
    if (key == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_TRACE, "Null pointer provided as key to "
Packit Service 31306d
                               "pki_key_check_hash_compatible()");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    switch(key->type) {
Packit Service 31306d
    case SSH_KEYTYPE_DSS_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_DSS:
Packit Service 31306d
        if (hash_type == SSH_DIGEST_SHA1) {
Packit Service 31306d
            if (ssh_fips_mode()) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "SHA1 is not allowed in FIPS mode");
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            } else {
Packit Service 31306d
                return SSH_OK;
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEYTYPE_RSA_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_RSA:
Packit Service 31306d
        if (hash_type == SSH_DIGEST_SHA1) {
Packit Service 31306d
            if (ssh_fips_mode()) {
Packit Service 31306d
                SSH_LOG(SSH_LOG_WARN, "SHA1 is not allowed in FIPS mode");
Packit Service 31306d
                return SSH_ERROR;
Packit Service 31306d
            } else {
Packit Service 31306d
                return SSH_OK;
Packit Service 31306d
            }
Packit Service 31306d
        }
Packit Service 31306d
Packit Service 31306d
        if (hash_type == SSH_DIGEST_SHA256 ||
Packit Service 31306d
            hash_type == SSH_DIGEST_SHA512)
Packit Service 31306d
        {
Packit Service 31306d
            return SSH_OK;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P256_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P256:
Packit Service 31306d
        if (hash_type == SSH_DIGEST_SHA256) {
Packit Service 31306d
            return SSH_OK;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P384_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P384:
Packit Service 31306d
        if (hash_type == SSH_DIGEST_SHA384) {
Packit Service 31306d
            return SSH_OK;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P521_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA_P521:
Packit Service 31306d
        if (hash_type == SSH_DIGEST_SHA512) {
Packit Service 31306d
            return SSH_OK;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEYTYPE_ED25519_CERT01:
Packit Service 31306d
    case SSH_KEYTYPE_ED25519:
Packit Service 31306d
        if (hash_type == SSH_DIGEST_AUTO) {
Packit Service 31306d
            return SSH_OK;
Packit Service 31306d
        }
Packit Service 31306d
        break;
Packit Service 31306d
    case SSH_KEYTYPE_RSA1:
Packit Service 31306d
    case SSH_KEYTYPE_ECDSA:
Packit Service 31306d
    case SSH_KEYTYPE_UNKNOWN:
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Unknown key type %d", key->type);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_WARN, "Key type %d incompatible with hash type  %d",
Packit Service 31306d
            key->type, hash_type);
Packit Service 31306d
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
int ssh_pki_signature_verify(ssh_session session,
Packit Service 31306d
                             ssh_signature sig,
Packit Service 31306d
                             const ssh_key key,
Packit Service 31306d
                             const unsigned char *input,
Packit Service 31306d
                             size_t input_len)
Packit Service 31306d
{
Packit Service 31306d
    int rc;
Packit Service 31306d
    enum ssh_keytypes_e key_type;
Packit Service 31306d
Packit Service 31306d
    if (session == NULL || sig == NULL || key == NULL || input == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
Packit Service 31306d
                               "ssh_pki_signature_verify()");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    key_type = ssh_key_type_plain(key->type);
Packit Service 31306d
Packit Service 31306d
    SSH_LOG(SSH_LOG_FUNCTIONS,
Packit Service 31306d
            "Going to verify a %s type signature",
Packit Service 31306d
            sig->type_c);
Packit Service 31306d
Packit Service 31306d
    if (key_type != sig->type) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN,
Packit Service 31306d
                "Can not verify %s signature with %s key",
Packit Service 31306d
                sig->type_c, key->type_c);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Check if public key and hash type are compatible */
Packit Service 31306d
    rc = pki_key_check_hash_compatible(key, sig->hash_type);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = pki_verify_data_signature(sig, key, input, input_len);
Packit Service 31306d
Packit Service 31306d
    return rc;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
ssh_signature pki_do_sign(const ssh_key privkey,
Packit Service 31306d
                          const unsigned char *input,
Packit Service 31306d
                          size_t input_len,
Packit Service 31306d
                          enum ssh_digest_e hash_type)
Packit Service 31306d
{
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (privkey == NULL || input == NULL) {
Packit Service 31306d
        SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
Packit Service 31306d
                               "pki_do_sign()");
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Check if public key and hash type are compatible */
Packit Service 31306d
    rc = pki_key_check_hash_compatible(privkey, hash_type);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return pki_sign_data(privkey, hash_type, input, input_len);
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/*
Packit Service 31306d
 * This function signs the session id as a string then
Packit Service 31306d
 * the content of sigbuf */
Packit Service 31306d
ssh_string ssh_pki_do_sign(ssh_session session,
Packit Service 31306d
                           ssh_buffer sigbuf,
Packit Service 31306d
                           const ssh_key privkey,
Packit Service 31306d
                           enum ssh_digest_e hash_type)
Packit Service 31306d
{
Packit Service 31306d
    struct ssh_crypto_struct *crypto = NULL;
Packit Service 31306d
Packit Service 31306d
    ssh_signature sig = NULL;
Packit Service 31306d
    ssh_string sig_blob = NULL;
Packit Service 31306d
Packit Service 31306d
    ssh_string session_id = NULL;
Packit Service 31306d
    ssh_buffer sign_input = NULL;
Packit Service 31306d
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (session == NULL || sigbuf == NULL || privkey == NULL ||
Packit Service 31306d
        !ssh_key_is_private(privkey))
Packit Service 31306d
    {
Packit Service 31306d
        SSH_LOG(SSH_LOG_TRACE, "Bad parameter provided to "
Packit Service 31306d
                               "ssh_pki_do_sign()");
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_BOTH);
Packit Service 31306d
    if (crypto == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Get the session ID */
Packit Service 31306d
    session_id = ssh_string_new(crypto->digest_len);
Packit Service 31306d
    if (session_id == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
    ssh_string_fill(session_id, crypto->session_id, crypto->digest_len);
Packit Service 31306d
Packit Service 31306d
    /* Fill the input */
Packit Service 31306d
    sign_input = ssh_buffer_new();
Packit Service 31306d
    if (sign_input == NULL) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
    ssh_buffer_set_secure(sign_input);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_pack(sign_input,
Packit Service 31306d
                         "SP",
Packit Service 31306d
                         session_id,
Packit Service 31306d
                         ssh_buffer_get_len(sigbuf), ssh_buffer_get(sigbuf));
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Generate the signature */
Packit Service 31306d
    sig = pki_do_sign(privkey,
Packit Service 31306d
            ssh_buffer_get(sign_input),
Packit Service 31306d
            ssh_buffer_get_len(sign_input),
Packit Service 31306d
            hash_type);
Packit Service 31306d
    if (sig == NULL) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Convert the signature to blob */
Packit Service 31306d
    rc = ssh_pki_export_signature_blob(sig, &sig_blob);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        sig_blob = NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
end:
Packit Service 31306d
    ssh_signature_free(sig);
Packit Service 31306d
    SSH_BUFFER_FREE(sign_input);
Packit Service 31306d
    SSH_STRING_FREE(session_id);
Packit Service 31306d
Packit Service 31306d
    return sig_blob;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
#ifndef _WIN32
Packit Service 31306d
ssh_string ssh_pki_do_sign_agent(ssh_session session,
Packit Service 31306d
                                 struct ssh_buffer_struct *buf,
Packit Service 31306d
                                 const ssh_key pubkey)
Packit Service 31306d
{
Packit Service 31306d
    struct ssh_crypto_struct *crypto = NULL;
Packit Service 31306d
    ssh_string session_id;
Packit Service 31306d
    ssh_string sig_blob;
Packit Service 31306d
    ssh_buffer sig_buf;
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    crypto = ssh_packet_get_current_crypto(session, SSH_DIRECTION_BOTH);
Packit Service 31306d
    if (crypto == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* prepend session identifier */
Packit Service 31306d
    session_id = ssh_string_new(crypto->digest_len);
Packit Service 31306d
    if (session_id == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
    ssh_string_fill(session_id, crypto->session_id, crypto->digest_len);
Packit Service 31306d
Packit Service 31306d
    sig_buf = ssh_buffer_new();
Packit Service 31306d
    if (sig_buf == NULL) {
Packit Service 31306d
        SSH_STRING_FREE(session_id);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_add_ssh_string(sig_buf, session_id);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        SSH_STRING_FREE(session_id);
Packit Service 31306d
        SSH_BUFFER_FREE(sig_buf);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
    SSH_STRING_FREE(session_id);
Packit Service 31306d
Packit Service 31306d
    /* append out buffer */
Packit Service 31306d
    if (ssh_buffer_add_buffer(sig_buf, buf) < 0) {
Packit Service 31306d
        SSH_BUFFER_FREE(sig_buf);
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* create signature */
Packit Service 31306d
    sig_blob = ssh_agent_sign_data(session, pubkey, sig_buf);
Packit Service 31306d
Packit Service 31306d
    SSH_BUFFER_FREE(sig_buf);
Packit Service 31306d
Packit Service 31306d
    return sig_blob;
Packit Service 31306d
}
Packit Service 31306d
#endif /* _WIN32 */
Packit Service 31306d
Packit Service 31306d
#ifdef WITH_SERVER
Packit Service 31306d
ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
Packit Service 31306d
                                         const ssh_key privkey,
Packit Service 31306d
                                         const enum ssh_digest_e digest)
Packit Service 31306d
{
Packit Service 31306d
    struct ssh_crypto_struct *crypto = NULL;
Packit Service 31306d
Packit Service 31306d
    ssh_signature sig = NULL;
Packit Service 31306d
    ssh_string sig_blob = NULL;
Packit Service 31306d
Packit Service 31306d
    ssh_buffer sign_input = NULL;
Packit Service 31306d
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (session == NULL || privkey == NULL || !ssh_key_is_private(privkey)) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    crypto = session->next_crypto ? session->next_crypto :
Packit Service 31306d
                                    session->current_crypto;
Packit Service 31306d
Packit Service 31306d
    if (crypto->secret_hash == NULL){
Packit Service 31306d
        ssh_set_error(session,SSH_FATAL,"Missing secret_hash");
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Fill the input */
Packit Service 31306d
    sign_input = ssh_buffer_new();
Packit Service 31306d
    if (sign_input == NULL) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
    ssh_buffer_set_secure(sign_input);
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_pack(sign_input,
Packit Service 31306d
                         "P",
Packit Service 31306d
                         crypto->digest_len,
Packit Service 31306d
                         crypto->secret_hash);
Packit Service 31306d
    if (rc != SSH_OK) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Generate the signature */
Packit Service 31306d
    sig = pki_do_sign(privkey,
Packit Service 31306d
            ssh_buffer_get(sign_input),
Packit Service 31306d
            ssh_buffer_get_len(sign_input),
Packit Service 31306d
            digest);
Packit Service 31306d
    if (sig == NULL) {
Packit Service 31306d
        goto end;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    /* Convert the signature to blob */
Packit Service 31306d
    rc = ssh_pki_export_signature_blob(sig, &sig_blob);
Packit Service 31306d
    if (rc < 0) {
Packit Service 31306d
        sig_blob = NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
end:
Packit Service 31306d
    ssh_signature_free(sig);
Packit Service 31306d
    SSH_BUFFER_FREE(sign_input);
Packit Service 31306d
Packit Service 31306d
    return sig_blob;
Packit Service 31306d
}
Packit Service 31306d
#endif /* WITH_SERVER */
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @}
Packit Service 31306d
 */