Blame src/pki_ed25519_common.c

Packit Service 31306d
/*
Packit Service 31306d
 * pki_ed25519_common.c - Common ed25519 functions
Packit Service 31306d
 *
Packit Service 31306d
 * This file is part of the SSH Library
Packit Service 31306d
 *
Packit Service 31306d
 * Copyright (c) 2014 by Aris Adamantiadis
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
#include "config.h"
Packit Service 31306d
Packit Service 31306d
#include "libssh/pki.h"
Packit Service 31306d
#include "libssh/pki_priv.h"
Packit Service 31306d
#include "libssh/buffer.h"
Packit Service 31306d
Packit Service 31306d
int pki_privkey_build_ed25519(ssh_key key,
Packit Service 31306d
                              ssh_string pubkey,
Packit Service 31306d
                              ssh_string privkey)
Packit Service 31306d
{
Packit Service 31306d
    if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
Packit Service 31306d
        ssh_string_len(privkey) != (2 * ED25519_KEY_LEN))
Packit Service 31306d
    {
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_OPENSSL_ED25519
Packit Service 31306d
    /* In OpenSSL implementation, the private key is the original private seed,
Packit Service 31306d
     * without the public key. */
Packit Service 31306d
    key->ed25519_privkey = malloc(ED25519_KEY_LEN);
Packit Service 31306d
#else
Packit Service 31306d
    /* In the internal implementation, the private key is the concatenation of
Packit Service 31306d
     * the private seed with the public key. */
Packit Service 31306d
    key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
Packit Service 31306d
#endif
Packit Service 31306d
    if (key->ed25519_privkey == NULL) {
Packit Service 31306d
        goto error;
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
        goto error;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_OPENSSL_ED25519
Packit Service 31306d
    memcpy(key->ed25519_privkey, ssh_string_data(privkey),
Packit Service 31306d
           ED25519_KEY_LEN);
Packit Service 31306d
#else
Packit Service 31306d
    memcpy(key->ed25519_privkey, ssh_string_data(privkey),
Packit Service 31306d
           2 * ED25519_KEY_LEN);
Packit Service 31306d
#endif
Packit Service 31306d
    memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
Packit Service 31306d
           ED25519_KEY_LEN);
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
Packit Service 31306d
error:
Packit Service 31306d
    SAFE_FREE(key->ed25519_privkey);
Packit Service 31306d
    SAFE_FREE(key->ed25519_pubkey);
Packit Service 31306d
Packit Service 31306d
    return SSH_ERROR;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Compare ed25519 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 pki_ed25519_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
    int cmp;
Packit Service 31306d
Packit Service 31306d
    switch(what) {
Packit Service 31306d
    case SSH_KEY_CMP_PRIVATE:
Packit Service 31306d
        if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
Packit Service 31306d
            return 1;
Packit Service 31306d
        }
Packit Service 31306d
#ifdef HAVE_OPENSSL_ED25519
Packit Service 31306d
        /* In OpenSSL implementation, the private key is the original private
Packit Service 31306d
         * seed, without the public key. */
Packit Service 31306d
        cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_KEY_LEN);
Packit Service 31306d
#else
Packit Service 31306d
        /* In the internal implementation, the private key is the concatenation
Packit Service 31306d
         * of the private seed with the public key. */
Packit Service 31306d
        cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey,
Packit Service 31306d
                     2 * ED25519_KEY_LEN);
Packit Service 31306d
#endif
Packit Service 31306d
        if (cmp != 0) {
Packit Service 31306d
            return 1;
Packit Service 31306d
        }
Packit Service 31306d
        /* FALL THROUGH */
Packit Service 31306d
    case SSH_KEY_CMP_PUBLIC:
Packit Service 31306d
        if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
Packit Service 31306d
            return 1;
Packit Service 31306d
        }
Packit Service 31306d
        cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN);
Packit Service 31306d
        if (cmp != 0) {
Packit Service 31306d
            return 1;
Packit Service 31306d
        }
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    return 0;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Duplicate an Ed25519 key
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] new Pre-initialized ssh_key structure
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] key Key to copy
Packit Service 31306d
 *
Packit Service 31306d
 * @return SSH_ERROR on error, SSH_OK on success
Packit Service 31306d
 */
Packit Service 31306d
int pki_ed25519_key_dup(ssh_key new, const ssh_key key)
Packit Service 31306d
{
Packit Service 31306d
    if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
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 the original private
Packit Service 31306d
         * seed, without the public key. */
Packit Service 31306d
        new->ed25519_privkey = malloc(ED25519_KEY_LEN);
Packit Service 31306d
#else
Packit Service 31306d
        /* In the internal implementation, the private key is the concatenation
Packit Service 31306d
         * of the private seed with the public key. */
Packit Service 31306d
        new->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
Packit Service 31306d
#endif
Packit Service 31306d
        if (new->ed25519_privkey == NULL) {
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
#ifdef HAVE_OPENSSL_ED25519
Packit Service 31306d
        memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_KEY_LEN);
Packit Service 31306d
#else
Packit Service 31306d
        memcpy(new->ed25519_privkey, key->ed25519_privkey, 2 * ED25519_KEY_LEN);
Packit Service 31306d
#endif
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    if (key->ed25519_pubkey != NULL) {
Packit Service 31306d
        new->ed25519_pubkey = malloc(ED25519_KEY_LEN);
Packit Service 31306d
        if (new->ed25519_pubkey == NULL) {
Packit Service 31306d
            SAFE_FREE(new->ed25519_privkey);
Packit Service 31306d
            return SSH_ERROR;
Packit Service 31306d
        }
Packit Service 31306d
        memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN);
Packit Service 31306d
    }
Packit Service 31306d
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 Outputs an Ed25519 public key in a blob buffer.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] buffer Output buffer
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] key Key to output
Packit Service 31306d
 *
Packit Service 31306d
 * @return SSH_ERROR on error, SSH_OK on success
Packit Service 31306d
 */
Packit Service 31306d
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
Packit Service 31306d
{
Packit Service 31306d
    int rc;
Packit Service 31306d
Packit Service 31306d
    if (key->ed25519_pubkey == NULL){
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
    rc = ssh_buffer_pack(buffer,
Packit Service 31306d
                         "dP",
Packit Service 31306d
                         (uint32_t)ED25519_KEY_LEN,
Packit Service 31306d
                         (size_t)ED25519_KEY_LEN, key->ed25519_pubkey);
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 output a signature blob from an ed25519 signature
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] sig signature to convert
Packit Service 31306d
 *
Packit Service 31306d
 * @return Signature blob in SSH string, or NULL on error
Packit Service 31306d
 */
Packit Service 31306d
ssh_string pki_ed25519_signature_to_blob(ssh_signature sig)
Packit Service 31306d
{
Packit Service 31306d
    ssh_string sig_blob;
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_OPENSSL_ED25519
Packit Service 31306d
    /* When using the OpenSSL implementation, the signature is stored in raw_sig
Packit Service 31306d
     * which is shared by all algorithms.*/
Packit Service 31306d
    if (sig->raw_sig == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
#else
Packit Service 31306d
    /* When using the internal implementation, the signature is stored in an
Packit Service 31306d
     * algorithm specific field. */
Packit Service 31306d
    if (sig->ed25519_sig == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    sig_blob = ssh_string_new(ED25519_SIG_LEN);
Packit Service 31306d
    if (sig_blob == NULL) {
Packit Service 31306d
        return NULL;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_OPENSSL_ED25519
Packit Service 31306d
    ssh_string_fill(sig_blob, ssh_string_data(sig->raw_sig),
Packit Service 31306d
                    ssh_string_len(sig->raw_sig));
Packit Service 31306d
#else
Packit Service 31306d
    ssh_string_fill(sig_blob, sig->ed25519_sig, ED25519_SIG_LEN);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    return sig_blob;
Packit Service 31306d
}
Packit Service 31306d
Packit Service 31306d
/**
Packit Service 31306d
 * @internal
Packit Service 31306d
 *
Packit Service 31306d
 * @brief Convert a signature blob in an ed25519 signature.
Packit Service 31306d
 *
Packit Service 31306d
 * @param[out] sig a preinitialized signature
Packit Service 31306d
 *
Packit Service 31306d
 * @param[in] sig_blob a signature blob
Packit Service 31306d
 *
Packit Service 31306d
 * @return SSH_ERROR on error, SSH_OK on success
Packit Service 31306d
 */
Packit Service 31306d
int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob)
Packit Service 31306d
{
Packit Service 31306d
    size_t len;
Packit Service 31306d
Packit Service 31306d
    len = ssh_string_len(sig_blob);
Packit Service 31306d
    if (len != ED25519_SIG_LEN){
Packit Service 31306d
        SSH_LOG(SSH_LOG_WARN, "Invalid ssh-ed25519 signature len: %zu", len);
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
Packit Service 31306d
#ifdef HAVE_OPENSSL_ED25519
Packit Service 31306d
    sig->raw_sig = ssh_string_copy(sig_blob);
Packit Service 31306d
#else
Packit Service 31306d
    sig->ed25519_sig = malloc(ED25519_SIG_LEN);
Packit Service 31306d
    if (sig->ed25519_sig == NULL){
Packit Service 31306d
        return SSH_ERROR;
Packit Service 31306d
    }
Packit Service 31306d
    memcpy(sig->ed25519_sig, ssh_string_data(sig_blob), ED25519_SIG_LEN);
Packit Service 31306d
#endif
Packit Service 31306d
Packit Service 31306d
    return SSH_OK;
Packit Service 31306d
}
Packit Service 31306d