Skip to content

Commit

Permalink
openssl/SignECDSA: do not use deprecated OpenSSL functions
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxKellermann committed Oct 23, 2023
1 parent 271a290 commit 1746bf5
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 16 deletions.
5 changes: 1 addition & 4 deletions src/key/ECDSAKey.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,8 @@ ECDSAKey::SerializeKex(SSH::Serializer &s) const
void
ECDSAKey::Sign(SSH::Serializer &s, std::span<const std::byte> src) const
{
auto *ec_key = EVP_PKEY_get1_EC_KEY(key.get());
AtScopeExit(ec_key) { EC_KEY_free(ec_key); };

constexpr int ec_nid = NID_X9_62_prime256v1; // TODO

SignECDSA(s, *ec_key, ec_nid, src);
SignECDSA(s, *key, ec_nid, src);

}
79 changes: 69 additions & 10 deletions src/openssl/SignECDSA.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
#include "SerializeBN.hxx"
#include "ssh/Serializer.hxx"
#include "lib/openssl/Error.hxx"
#include "lib/openssl/UniqueEVP.hxx"
#include "util/ScopeExit.hxx"
#include "Digest.hxx"

#include <openssl/obj_mac.h>
#include <openssl/ec.h>
#include <openssl/rsa.h>

#include <sodium/utils.h>

Expand Down Expand Up @@ -45,27 +47,84 @@ sshkey_ec_nid_to_hash_alg(int nid)
return DigestAlgorithm::SHA512;
}

static void
SignDigestOpenSSL(SSH::Serializer &s,
EVP_PKEY_CTX &ctx, std::span<const std::byte> digest)
{
size_t length;
if (EVP_PKEY_sign(&ctx, nullptr, &length,
reinterpret_cast<const unsigned char *>(digest.data()),
digest.size()) <= 0)
throw SslError{"EVP_PKEY_sign() failed"};

auto dest = s.BeginWriteN(length);
if (EVP_PKEY_sign(&ctx,
reinterpret_cast<unsigned char *>(dest.data()), &length,
reinterpret_cast<const unsigned char *>(digest.data()),
digest.size()) <= 0)
throw SslError{"EVP_PKEY_sign() failed"};

s.CommitWriteN(length);
}

static void
SignDigestOpenSSL(SSH::Serializer &s,
EVP_PKEY &key,
std::span<const std::byte> digest)
{
const UniqueEVP_PKEY_CTX ctx(EVP_PKEY_CTX_new(&key, nullptr));
if (!ctx)
throw SslError("EVP_PKEY_CTX_new() failed");

if (EVP_PKEY_sign_init(ctx.get()) <= 0)
throw SslError("EVP_PKEY_sign_init() failed");

if (EVP_PKEY_CTX_set_signature_md(ctx.get(), EVP_sha256()) <= 0)
throw SslError("EVP_PKEY_CTX_set_signature_md() failed");

SignDigestOpenSSL(s, *ctx, digest);
}

static void
SignOpenSSL(SSH::Serializer &s,
EVP_PKEY &key, int ecdsa_nid,
std::span<const std::byte> src)
{
const auto hash_alg = sshkey_ec_nid_to_hash_alg(ecdsa_nid);

std::byte digest_buffer[DIGEST_MAX_SIZE];
Digest(hash_alg, src, digest_buffer);
AtScopeExit(&digest_buffer) { sodium_memzero(digest_buffer, sizeof(digest_buffer)); };

const std::span digest{digest_buffer, DigestSize(hash_alg)};
SignDigestOpenSSL(s, key, digest);
}

void
SignECDSA(SSH::Serializer &s,
EC_KEY &key, int ecdsa_nid,
EVP_PKEY &key, int ecdsa_nid,
std::span<const std::byte> src)
{
const auto hash_alg = sshkey_ec_nid_to_hash_alg(ecdsa_nid);
const std::size_t hlen = DigestSize(hash_alg);
/* write the raw signature to the serializer, convert to
ECDSA_SIG (and rewind so we can serialize it again, but
this time in SSH format) */
const auto signature_mark = s.Mark();
SignOpenSSL(s, key, ecdsa_nid, src);
const auto signature = s.Since(signature_mark);
s.Rewind(signature_mark);

std::byte digest[DIGEST_MAX_SIZE];
Digest(hash_alg, src, digest);
AtScopeExit(&digest) { sodium_memzero(digest, sizeof(digest)); };

ECDSA_SIG *esig = ECDSA_do_sign(reinterpret_cast<const unsigned char *>(digest), hlen, &key);
if (esig == nullptr)
auto signature_data = reinterpret_cast<const unsigned char *>(signature.data());
ECDSA_SIG *esig = d2i_ECDSA_SIG(nullptr, &signature_data, signature.size());
if (esig == nullptr)
throw SslError{};

AtScopeExit(esig) { ECDSA_SIG_free(esig); };

const BIGNUM *sig_r, *sig_s;
ECDSA_SIG_get0(esig, &sig_r, &sig_s);

/* now serialize in SSH format */

constexpr auto signature_type = "ecdsa-sha2-nistp256"sv; // TODO
s.WriteString(signature_type);

Expand Down
4 changes: 2 additions & 2 deletions src/openssl/SignECDSA.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#pragma once

#include <openssl/ec.h>
#include <openssl/evp.h>

#include <cstddef>
#include <span>
Expand All @@ -13,5 +13,5 @@ namespace SSH { class Serializer; }

void
SignECDSA(SSH::Serializer &s,
EC_KEY &key, int ecdsa_nid,
EVP_PKEY &key, int ecdsa_nid,
std::span<const std::byte> src);
8 changes: 8 additions & 0 deletions src/ssh/Serializer.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,15 @@ public:
return position;
}

constexpr void Rewind(std::size_t old_position) noexcept {
assert(position >= old_position);

position = old_position;
}

constexpr std::span<const std::byte> Since(std::size_t old_position) const noexcept {
assert(position >= old_position);

return std::span{buffer}.first(position).subspan(old_position);
}

Expand Down

0 comments on commit 1746bf5

Please sign in to comment.