1
1
libssh/src/pki_ed25519_common.c

286 строки
7.6 KiB
C
Исходник Обычный вид История

/*
* pki_ed25519_common.c - Common ed25519 functions
*
* This file is part of the SSH Library
*
* Copyright (c) 2014 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*/
#include "config.h"
#include "libssh/pki.h"
#include "libssh/pki_priv.h"
#include "libssh/buffer.h"
int pki_privkey_build_ed25519(ssh_key key,
ssh_string pubkey,
ssh_string privkey)
{
if (ssh_string_len(pubkey) != ED25519_KEY_LEN ||
ssh_string_len(privkey) != (2 * ED25519_KEY_LEN))
{
SSH_LOG(SSH_LOG_WARN, "Invalid ed25519 key len");
return SSH_ERROR;
}
#ifdef HAVE_OPENSSL_ED25519
/* In OpenSSL implementation, the private key is the original private seed,
* without the public key. */
key->ed25519_privkey = malloc(ED25519_KEY_LEN);
#else
/* In the internal implementation, the private key is the concatenation of
* the private seed with the public key. */
key->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
#endif
if (key->ed25519_privkey == NULL) {
goto error;
}
key->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (key->ed25519_pubkey == NULL) {
goto error;
}
#ifdef HAVE_OPENSSL_ED25519
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
ED25519_KEY_LEN);
#else
memcpy(key->ed25519_privkey, ssh_string_data(privkey),
2 * ED25519_KEY_LEN);
#endif
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey),
ED25519_KEY_LEN);
return SSH_OK;
error:
SAFE_FREE(key->ed25519_privkey);
SAFE_FREE(key->ed25519_pubkey);
return SSH_ERROR;
}
/**
* @internal
*
* @brief Compare ed25519 keys if they are equal.
*
* @param[in] k1 The first key to compare.
*
* @param[in] k2 The second key to compare.
*
* @param[in] what What part or type of the key do you want to compare.
*
* @return 0 if equal, 1 if not.
*/
int pki_ed25519_key_cmp(const ssh_key k1,
const ssh_key k2,
enum ssh_keycmp_e what)
{
int cmp;
switch(what) {
case SSH_KEY_CMP_PRIVATE:
if (k1->ed25519_privkey == NULL || k2->ed25519_privkey == NULL) {
return 1;
}
#ifdef HAVE_OPENSSL_ED25519
/* In OpenSSL implementation, the private key is the original private
* seed, without the public key. */
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_KEY_LEN);
#else
/* In the internal implementation, the private key is the concatenation
* of the private seed with the public key. */
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey,
2 * ED25519_KEY_LEN);
#endif
if (cmp != 0) {
return 1;
}
FALL_THROUGH;
case SSH_KEY_CMP_PUBLIC:
if (k1->ed25519_pubkey == NULL || k2->ed25519_pubkey == NULL) {
return 1;
}
cmp = memcmp(k1->ed25519_pubkey, k2->ed25519_pubkey, ED25519_KEY_LEN);
if (cmp != 0) {
return 1;
}
}
return 0;
}
/**
* @internal
*
* @brief Duplicate an Ed25519 key
*
* @param[out] new Pre-initialized ssh_key structure
*
* @param[in] key Key to copy
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_key_dup(ssh_key new, const ssh_key key)
{
if (key->ed25519_privkey == NULL && key->ed25519_pubkey == NULL) {
return SSH_ERROR;
}
if (key->ed25519_privkey != NULL) {
#ifdef HAVE_OPENSSL_ED25519
/* In OpenSSL implementation, the private key is the original private
* seed, without the public key. */
new->ed25519_privkey = malloc(ED25519_KEY_LEN);
#else
/* In the internal implementation, the private key is the concatenation
* of the private seed with the public key. */
new->ed25519_privkey = malloc(2 * ED25519_KEY_LEN);
#endif
if (new->ed25519_privkey == NULL) {
return SSH_ERROR;
}
#ifdef HAVE_OPENSSL_ED25519
memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_KEY_LEN);
#else
memcpy(new->ed25519_privkey, key->ed25519_privkey, 2 * ED25519_KEY_LEN);
#endif
}
if (key->ed25519_pubkey != NULL) {
new->ed25519_pubkey = malloc(ED25519_KEY_LEN);
if (new->ed25519_pubkey == NULL) {
SAFE_FREE(new->ed25519_privkey);
return SSH_ERROR;
}
memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_KEY_LEN);
}
return SSH_OK;
}
/**
* @internal
*
* @brief Outputs an Ed25519 public key in a blob buffer.
*
* @param[out] buffer Output buffer
*
* @param[in] key Key to output
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key)
{
int rc;
if (key->ed25519_pubkey == NULL){
return SSH_ERROR;
}
rc = ssh_buffer_pack(buffer,
"dP",
(uint32_t)ED25519_KEY_LEN,
(size_t)ED25519_KEY_LEN, key->ed25519_pubkey);
return rc;
}
/**
* @internal
*
* @brief output a signature blob from an ed25519 signature
*
* @param[in] sig signature to convert
*
* @return Signature blob in SSH string, or NULL on error
*/
ssh_string pki_ed25519_signature_to_blob(ssh_signature sig)
{
ssh_string sig_blob;
int rc;
#ifdef HAVE_OPENSSL_ED25519
/* When using the OpenSSL implementation, the signature is stored in raw_sig
* which is shared by all algorithms.*/
if (sig->raw_sig == NULL) {
return NULL;
}
#else
/* When using the internal implementation, the signature is stored in an
* algorithm specific field. */
if (sig->ed25519_sig == NULL) {
return NULL;
}
#endif
sig_blob = ssh_string_new(ED25519_SIG_LEN);
if (sig_blob == NULL) {
return NULL;
}
#ifdef HAVE_OPENSSL_ED25519
rc = ssh_string_fill(sig_blob, ssh_string_data(sig->raw_sig),
ssh_string_len(sig->raw_sig));
#else
rc = ssh_string_fill(sig_blob, sig->ed25519_sig, ED25519_SIG_LEN);
#endif
if (rc < 0) {
SSH_STRING_FREE(sig_blob);
return NULL;
}
return sig_blob;
}
/**
* @internal
*
* @brief Convert a signature blob in an ed25519 signature.
*
* @param[out] sig a preinitialized signature
*
* @param[in] sig_blob a signature blob
*
* @return SSH_ERROR on error, SSH_OK on success
*/
int pki_signature_from_ed25519_blob(ssh_signature sig, ssh_string sig_blob)
{
size_t len;
len = ssh_string_len(sig_blob);
if (len != ED25519_SIG_LEN){
SSH_LOG(SSH_LOG_WARN, "Invalid ssh-ed25519 signature len: %zu", len);
return SSH_ERROR;
}
#ifdef HAVE_OPENSSL_ED25519
sig->raw_sig = ssh_string_copy(sig_blob);
#else
sig->ed25519_sig = malloc(ED25519_SIG_LEN);
if (sig->ed25519_sig == NULL){
return SSH_ERROR;
}
memcpy(sig->ed25519_sig, ssh_string_data(sig_blob), ED25519_SIG_LEN);
#endif
return SSH_OK;
}