mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-08-08 19:02:06 +03:00
ed25519: Generate, sign and verify keys.
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#ifndef PKI_H_
|
||||
#define PKI_H_
|
||||
|
||||
#include "libssh/priv.h"
|
||||
#ifdef HAVE_OPENSSL_EC_H
|
||||
#include <openssl/ec.h>
|
||||
#endif
|
||||
@@ -29,6 +30,7 @@
|
||||
#endif
|
||||
|
||||
#include "libssh/crypto.h"
|
||||
#include "libssh/ed25519.h"
|
||||
|
||||
#define MAX_PUBKEY_SIZE 0x100000 /* 1M */
|
||||
#define MAX_PRIVKEY_SIZE 0x400000 /* 4M */
|
||||
@@ -55,6 +57,8 @@ struct ssh_key_struct {
|
||||
void *ecdsa;
|
||||
#endif /* HAVE_OPENSSL_EC_H */
|
||||
#endif
|
||||
ed25519_pubkey *ed25519_pubkey;
|
||||
ed25519_privkey *ed25519_privkey;
|
||||
void *cert;
|
||||
};
|
||||
|
||||
@@ -74,6 +78,7 @@ struct ssh_signature_struct {
|
||||
void *ecdsa_sig;
|
||||
# endif
|
||||
#endif
|
||||
ed25519_signature *ed25519_sig;
|
||||
};
|
||||
|
||||
typedef struct ssh_signature_struct *ssh_signature;
|
||||
|
@@ -41,6 +41,8 @@ ssh_key pki_key_dup(const ssh_key key, int demote);
|
||||
int pki_key_generate_rsa(ssh_key key, int parameter);
|
||||
int pki_key_generate_dss(ssh_key key, int parameter);
|
||||
int pki_key_generate_ecdsa(ssh_key key, int parameter);
|
||||
int pki_key_generate_ed25519(ssh_key key);
|
||||
|
||||
int pki_key_compare(const ssh_key k1,
|
||||
const ssh_key k2,
|
||||
enum ssh_keycmp_e what);
|
||||
@@ -91,4 +93,16 @@ ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
ssh_signature pki_do_sign_sessionid(const ssh_key key,
|
||||
const unsigned char *hash,
|
||||
size_t hlen);
|
||||
int pki_ed25519_sign(const ssh_key privkey, ssh_signature sig,
|
||||
const unsigned char *hash, size_t hlen);
|
||||
int pki_ed25519_verify(const ssh_key pubkey, ssh_signature sig,
|
||||
const unsigned char *hash, size_t hlen);
|
||||
int pki_ed25519_key_cmp(const ssh_key k1,
|
||||
const ssh_key k2,
|
||||
enum ssh_keycmp_e what);
|
||||
int pki_ed25519_key_dup(ssh_key new, const ssh_key key);
|
||||
int pki_ed25519_public_key_to_blob(ssh_buffer buffer, ssh_key key);
|
||||
ssh_string pki_ed25519_sig_to_blob(ssh_signature sig);
|
||||
int pki_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob);
|
||||
|
||||
#endif /* PKI_PRIV_H_ */
|
||||
|
@@ -139,6 +139,7 @@ set(libssh_SRCS
|
||||
packet_crypt.c
|
||||
pcap.c
|
||||
pki.c
|
||||
pki_ed25519.c
|
||||
poll.c
|
||||
session.c
|
||||
sc25519.c
|
||||
|
81
src/pki.c
81
src/pki.c
@@ -157,6 +157,11 @@ void ssh_key_clean (ssh_key key){
|
||||
if(key->ecdsa) EC_KEY_free(key->ecdsa);
|
||||
#endif /* HAVE_OPENSSL_ECC */
|
||||
#endif
|
||||
if (key->ed25519_privkey != NULL){
|
||||
BURN_BUFFER(key->ed25519_privkey, sizeof(ed25519_privkey));
|
||||
SAFE_FREE(key->ed25519_privkey);
|
||||
}
|
||||
SAFE_FREE(key->ed25519_pubkey);
|
||||
key->flags=SSH_KEY_FLAG_EMPTY;
|
||||
key->type=SSH_KEYTYPE_UNKNOWN;
|
||||
key->ecdsa_nid = 0;
|
||||
@@ -207,6 +212,8 @@ const char *ssh_key_type_to_char(enum ssh_keytypes_e type) {
|
||||
return "ssh-rsa1";
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
return "ssh-ecdsa";
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
return "ssh-ed25519";
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
return NULL;
|
||||
}
|
||||
@@ -245,6 +252,8 @@ enum ssh_keytypes_e ssh_key_type_from_name(const char *name) {
|
||||
|| strcmp(name, "ecdsa-sha2-nistp384") == 0
|
||||
|| strcmp(name, "ecdsa-sha2-nistp521") == 0) {
|
||||
return SSH_KEYTYPE_ECDSA;
|
||||
} else if (strcmp(name, "ssh-ed25519") == 0){
|
||||
return SSH_KEYTYPE_ED25519;
|
||||
}
|
||||
|
||||
return SSH_KEYTYPE_UNKNOWN;
|
||||
@@ -300,7 +309,7 @@ int ssh_key_cmp(const ssh_key k1,
|
||||
}
|
||||
|
||||
if (k1->type != k2->type) {
|
||||
ssh_pki_log("key types don't macth!");
|
||||
ssh_pki_log("key types don't match!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -311,6 +320,10 @@ int ssh_key_cmp(const ssh_key k1,
|
||||
}
|
||||
}
|
||||
|
||||
if (k1->type == SSH_KEYTYPE_ED25519) {
|
||||
return pki_ed25519_key_cmp(k1, k2, what);
|
||||
}
|
||||
|
||||
return pki_key_compare(k1, k2, what);
|
||||
}
|
||||
|
||||
@@ -354,6 +367,9 @@ void ssh_signature_free(ssh_signature sig)
|
||||
ECDSA_SIG_free(sig->ecdsa_sig);
|
||||
#endif
|
||||
break;
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
SAFE_FREE(sig->ed25519_sig);
|
||||
break;
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
break;
|
||||
}
|
||||
@@ -749,7 +765,26 @@ static int pki_import_pubkey_buffer(ssh_buffer buffer,
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
{
|
||||
ssh_string pubkey = buffer_get_ssh_string(buffer);
|
||||
|
||||
if (ssh_string_len(pubkey) != ED25519_PK_LEN) {
|
||||
ssh_pki_log("Invalid public key length");
|
||||
}
|
||||
|
||||
key->ed25519_pubkey = malloc(ED25519_PK_LEN);
|
||||
if (key->ed25519_pubkey == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(key->ed25519_pubkey, ssh_string_data(pubkey), ED25519_PK_LEN);
|
||||
ssh_string_burn(pubkey);
|
||||
ssh_string_free(pubkey);
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
ssh_pki_log("Unknown public key protocol %d", type);
|
||||
goto fail;
|
||||
}
|
||||
@@ -1010,6 +1045,12 @@ int ssh_pki_generate(enum ssh_keytypes_e type, int parameter,
|
||||
key->type_c = ssh_pki_key_ecdsa_name(key);
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
rc = pki_key_generate_ed25519(key);
|
||||
if (rc == SSH_ERROR) {
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
goto error;
|
||||
}
|
||||
@@ -1336,6 +1377,8 @@ int ssh_pki_signature_verify_blob(ssh_session session,
|
||||
ehash,
|
||||
elen);
|
||||
#endif
|
||||
} else if (key->type == SSH_KEYTYPE_ED25519) {
|
||||
rc = pki_signature_verify(session, sig, key, digest, dlen);
|
||||
} else {
|
||||
unsigned char hash[SHA_DIGEST_LEN] = {0};
|
||||
|
||||
@@ -1402,6 +1445,25 @@ ssh_string ssh_pki_do_sign(ssh_session session,
|
||||
|
||||
sig = pki_do_sign(privkey, ehash, elen);
|
||||
#endif
|
||||
} else if (privkey->type == SSH_KEYTYPE_ED25519){
|
||||
ssh_buffer buf;
|
||||
|
||||
buf = ssh_buffer_new();
|
||||
if (buf == NULL){
|
||||
ssh_string_free(session_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssh_buffer_set_secure(buf);
|
||||
ssh_buffer_pack(buf,
|
||||
"SP",
|
||||
session_id,
|
||||
buffer_get_rest_len(sigbuf), buffer_get_rest(sigbuf));
|
||||
|
||||
sig = pki_do_sign(privkey,
|
||||
ssh_buffer_get_begin(buf),
|
||||
ssh_buffer_get_len(buf));
|
||||
ssh_buffer_free(buf);
|
||||
} else {
|
||||
unsigned char hash[SHA_DIGEST_LEN] = {0};
|
||||
SHACTX ctx;
|
||||
@@ -1525,6 +1587,23 @@ ssh_string ssh_srv_pki_do_sign_sessionid(ssh_session session,
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
} else if (privkey->type == SSH_KEYTYPE_ED25519) {
|
||||
sig = ssh_signature_new();
|
||||
if (sig == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sig->type = privkey->type;
|
||||
sig->type_c = privkey->type_c;
|
||||
|
||||
rc = pki_ed25519_sign(privkey,
|
||||
sig,
|
||||
crypto->secret_hash,
|
||||
crypto->digest_len);
|
||||
if (rc != SSH_OK){
|
||||
ssh_signature_free(sig);
|
||||
sig = NULL;
|
||||
}
|
||||
} else {
|
||||
unsigned char hash[SHA_DIGEST_LEN] = {0};
|
||||
SHACTX ctx;
|
||||
|
@@ -214,6 +214,7 @@ int pki_pubkey_build_ecdsa(ssh_key key, int nid, ssh_string e)
|
||||
ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
{
|
||||
ssh_key new;
|
||||
int rc;
|
||||
|
||||
new = ssh_key_new();
|
||||
if (new == NULL) {
|
||||
@@ -371,7 +372,14 @@ ssh_key pki_key_dup(const ssh_key key, int demote)
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
rc = pki_ed25519_key_dup(new, key);
|
||||
if (rc != SSH_OK) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
ssh_key_free(new);
|
||||
return NULL;
|
||||
}
|
||||
@@ -533,7 +541,10 @@ int pki_key_compare(const ssh_key k1,
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
/* ed25519 keys handled globaly */
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -636,6 +647,7 @@ ssh_string pki_private_key_to_pem(const ssh_key key,
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
BIO_free(mem);
|
||||
ssh_pki_log("Unkown or invalid private key type %d", key->type);
|
||||
@@ -759,6 +771,7 @@ ssh_key pki_private_key_from_base64(const char *b64_key,
|
||||
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
BIO_free(mem);
|
||||
ssh_pki_log("Unkown or invalid private key type %d", type);
|
||||
@@ -997,7 +1010,14 @@ ssh_string pki_publickey_to_blob(const ssh_key key)
|
||||
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
rc = pki_ed25519_public_key_to_blob(buffer, key);
|
||||
if (rc == SSH_ERROR){
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@@ -1216,6 +1236,10 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
sig_blob = pki_ed25519_sig_to_blob(sig);
|
||||
break;
|
||||
default:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
ssh_pki_log("Unknown signature key type: %s", sig->type_c);
|
||||
return NULL;
|
||||
@@ -1293,6 +1317,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
ssh_string r;
|
||||
ssh_string s;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
sig = ssh_signature_new();
|
||||
if (sig == NULL) {
|
||||
@@ -1369,7 +1394,6 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
{ /* build ecdsa siganature */
|
||||
ssh_buffer b;
|
||||
uint32_t rlen;
|
||||
int rc;
|
||||
|
||||
b = ssh_buffer_new();
|
||||
if (b == NULL) {
|
||||
@@ -1437,6 +1461,14 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
|
||||
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
rc = pki_ed25519_sig_from_blob(sig, sig_blob);
|
||||
if (rc == SSH_ERROR){
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
ssh_pki_log("Unknown signature type");
|
||||
ssh_signature_free(sig);
|
||||
@@ -1484,6 +1516,15 @@ int pki_signature_verify(ssh_session session,
|
||||
return SSH_ERROR;
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
rc = pki_ed25519_verify(key, sig, hash, hlen);
|
||||
if (rc != SSH_OK){
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"ed25519 signature verification error");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_ECDSA:
|
||||
#ifdef HAVE_OPENSSL_ECC
|
||||
rc = ECDSA_do_verify(hash,
|
||||
@@ -1500,6 +1541,7 @@ int pki_signature_verify(ssh_session session,
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
ssh_set_error(session, SSH_FATAL, "Unknown public key type");
|
||||
return SSH_ERROR;
|
||||
}
|
||||
@@ -1511,6 +1553,7 @@ ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
const unsigned char *hash,
|
||||
size_t hlen) {
|
||||
ssh_signature sig;
|
||||
int rc;
|
||||
|
||||
sig = ssh_signature_new();
|
||||
if (sig == NULL) {
|
||||
@@ -1558,7 +1601,15 @@ ssh_signature pki_do_sign(const ssh_key privkey,
|
||||
|
||||
break;
|
||||
#endif /* HAVE_OPENSSL_ECC */
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
rc = pki_ed25519_sign(privkey, sig, hash, hlen);
|
||||
if (rc != SSH_OK){
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1605,7 +1656,10 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key,
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case SSH_KEYTYPE_ED25519:
|
||||
/* ED25519 handled in caller */
|
||||
case SSH_KEYTYPE_UNKNOWN:
|
||||
default:
|
||||
ssh_signature_free(sig);
|
||||
return NULL;
|
||||
}
|
||||
|
305
src/pki_ed25519.c
Normal file
305
src/pki_ed25519.c
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* pki_ed25519 .c - PKI infrastructure using ed25519
|
||||
*
|
||||
* 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 "libssh/pki.h"
|
||||
#include "libssh/pki_priv.h"
|
||||
#include "libssh/ed25519.h"
|
||||
#include "libssh/buffer.h"
|
||||
|
||||
int pki_key_generate_ed25519(ssh_key key)
|
||||
{
|
||||
int rc;
|
||||
|
||||
key->ed25519_privkey = malloc(sizeof (ed25519_privkey));
|
||||
if (key->ed25519_privkey == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
key->ed25519_pubkey = malloc(sizeof (ed25519_privkey));
|
||||
if (key->ed25519_privkey == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = crypto_sign_ed25519_keypair(*key->ed25519_pubkey,
|
||||
*key->ed25519_privkey);
|
||||
if (rc != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return SSH_OK;
|
||||
error:
|
||||
SAFE_FREE(key->ed25519_privkey);
|
||||
SAFE_FREE(key->ed25519_pubkey);
|
||||
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
int pki_ed25519_sign(const ssh_key privkey,
|
||||
ssh_signature sig,
|
||||
const unsigned char *hash,
|
||||
size_t hlen)
|
||||
{
|
||||
uint8_t *buffer = malloc(hlen + ED25519_SIG_LEN);
|
||||
unsigned long long dlen = 0;
|
||||
int rc;
|
||||
|
||||
buffer = malloc(hlen + ED25519_SIG_LEN);
|
||||
if (buffer == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
rc = crypto_sign_ed25519(buffer,
|
||||
&dlen,
|
||||
hash,
|
||||
hlen,
|
||||
*privkey->ed25519_privkey);
|
||||
if (rc != 0) {
|
||||
goto error;
|
||||
}
|
||||
sig->ed25519_sig = malloc(ED25519_SIG_LEN);
|
||||
if (sig->ed25519_sig == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* This shouldn't happen */
|
||||
if (dlen - hlen != ED25519_SIG_LEN) {
|
||||
goto error;
|
||||
}
|
||||
memcpy(sig->ed25519_sig, buffer, dlen - hlen);
|
||||
SAFE_FREE(buffer);
|
||||
|
||||
return SSH_OK;
|
||||
error:
|
||||
SAFE_FREE(buffer);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
int pki_ed25519_verify(const ssh_key pubkey,
|
||||
ssh_signature sig,
|
||||
const unsigned char *hash,
|
||||
size_t hlen)
|
||||
{
|
||||
unsigned long long mlen = 0;
|
||||
uint8_t *buffer;
|
||||
uint8_t *buffer2;
|
||||
int rc;
|
||||
|
||||
if (pubkey == NULL || sig == NULL ||
|
||||
hash == NULL || sig->ed25519_sig == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
buffer = malloc(hlen + ED25519_SIG_LEN);
|
||||
if (buffer == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
buffer2 = malloc(hlen + ED25519_SIG_LEN);
|
||||
if (buffer2 == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(buffer, sig->ed25519_sig, ED25519_SIG_LEN);
|
||||
memcpy(buffer + ED25519_SIG_LEN, hash, hlen);
|
||||
|
||||
rc = crypto_sign_ed25519_open(buffer2,
|
||||
&mlen,
|
||||
buffer,
|
||||
hlen + ED25519_SIG_LEN,
|
||||
*pubkey->ed25519_pubkey);
|
||||
|
||||
BURN_BUFFER(buffer, hlen + ED25519_SIG_LEN);
|
||||
BURN_BUFFER(buffer2, hlen);
|
||||
SAFE_FREE(buffer);
|
||||
SAFE_FREE(buffer2);
|
||||
if (rc == 0) {
|
||||
return SSH_OK;
|
||||
} else {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
error:
|
||||
SAFE_FREE(buffer);
|
||||
SAFE_FREE(buffer2);
|
||||
|
||||
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;
|
||||
}
|
||||
cmp = memcmp(k1->ed25519_privkey, k2->ed25519_privkey, ED25519_SK_LEN);
|
||||
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_PK_LEN);
|
||||
if (cmp != 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @brief duplicate an ed25519 key
|
||||
*
|
||||
* @param[out\ new preinitialized output ssh_ke
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
new->ed25519_privkey = malloc(ED25519_SK_LEN);
|
||||
if (new->ed25519_privkey == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
new->ed25519_pubkey = malloc(ED25519_PK_LEN);
|
||||
if (new->ed25519_privkey == NULL || new->ed25519_pubkey == NULL){
|
||||
SAFE_FREE(new->ed25519_privkey);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
memcpy(new->ed25519_privkey, key->ed25519_privkey, ED25519_SK_LEN);
|
||||
memcpy(new->ed25519_pubkey, key->ed25519_pubkey, ED25519_PK_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_PK_LEN,
|
||||
(size_t)ED25519_PK_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_sig_to_blob(ssh_signature sig)
|
||||
{
|
||||
ssh_string sig_blob;
|
||||
|
||||
if (sig->ed25519_sig == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sig_blob = ssh_string_new(ED25519_SIG_LEN);
|
||||
if (sig_blob == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
ssh_string_fill(sig_blob, sig->ed25519_sig, ED25519_SIG_LEN);
|
||||
|
||||
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_ed25519_sig_from_blob(ssh_signature sig, ssh_string sig_blob)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = ssh_string_len(sig_blob);
|
||||
if (len != ED25519_SIG_LEN){
|
||||
ssh_pki_log("Invalid ssh-ed25519 signature len: %zu", len);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return SSH_OK;
|
||||
}
|
Reference in New Issue
Block a user