summaryrefslogtreecommitdiff
path: root/libs/libssh2/src/mbedtls.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libssh2/src/mbedtls.c')
-rw-r--r--libs/libssh2/src/mbedtls.c1533
1 files changed, 1533 insertions, 0 deletions
diff --git a/libs/libssh2/src/mbedtls.c b/libs/libssh2/src/mbedtls.c
new file mode 100644
index 0000000000..a66e36c5ab
--- /dev/null
+++ b/libs/libssh2/src/mbedtls.c
@@ -0,0 +1,1533 @@
+/* Copyright (C) Art <https://github.com/wildart>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the copyright holder nor the names
+ * of any other contributors may be used to endorse or
+ * promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifdef LIBSSH2_CRYPTO_C /* Compile this via crypto.c */
+
+#include <stdlib.h>
+
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
+#define mbedtls_cipher_info_get_key_bitlen(c) (c->key_bitlen)
+#define mbedtls_cipher_info_get_iv_size(c) (c->iv_size)
+#define mbedtls_rsa_get_len(rsa) (rsa->len)
+
+#define MBEDTLS_PRIVATE(m) m
+#endif
+
+/*******************************************************************/
+/*
+ * mbedTLS backend: Global context handles
+ */
+
+static mbedtls_entropy_context _libssh2_mbedtls_entropy;
+static mbedtls_ctr_drbg_context _libssh2_mbedtls_ctr_drbg;
+
+/*******************************************************************/
+/*
+ * mbedTLS backend: Generic functions
+ */
+
+void
+_libssh2_mbedtls_init(void)
+{
+ int ret;
+
+ mbedtls_entropy_init(&_libssh2_mbedtls_entropy);
+ mbedtls_ctr_drbg_init(&_libssh2_mbedtls_ctr_drbg);
+
+ ret = mbedtls_ctr_drbg_seed(&_libssh2_mbedtls_ctr_drbg,
+ mbedtls_entropy_func,
+ &_libssh2_mbedtls_entropy, NULL, 0);
+ if(ret)
+ mbedtls_ctr_drbg_free(&_libssh2_mbedtls_ctr_drbg);
+}
+
+void
+_libssh2_mbedtls_free(void)
+{
+ mbedtls_ctr_drbg_free(&_libssh2_mbedtls_ctr_drbg);
+ mbedtls_entropy_free(&_libssh2_mbedtls_entropy);
+}
+
+int
+_libssh2_mbedtls_random(unsigned char *buf, size_t len)
+{
+ int ret;
+ ret = mbedtls_ctr_drbg_random(&_libssh2_mbedtls_ctr_drbg, buf, len);
+ return ret == 0 ? 0 : -1;
+}
+
+static void
+_libssh2_mbedtls_safe_free(void *buf, size_t len)
+{
+ if(!buf)
+ return;
+
+ if(len > 0)
+ _libssh2_explicit_zero(buf, len);
+
+ mbedtls_free(buf);
+}
+
+int
+_libssh2_mbedtls_cipher_init(_libssh2_cipher_ctx *ctx,
+ _libssh2_cipher_type(algo),
+ unsigned char *iv,
+ unsigned char *secret,
+ int encrypt)
+{
+ const mbedtls_cipher_info_t *cipher_info;
+ int ret, op;
+
+ if(!ctx)
+ return -1;
+
+ op = encrypt == 0 ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT;
+
+ cipher_info = mbedtls_cipher_info_from_type(algo);
+ if(!cipher_info)
+ return -1;
+
+ mbedtls_cipher_init(ctx);
+ ret = mbedtls_cipher_setup(ctx, cipher_info);
+ if(!ret)
+ ret = mbedtls_cipher_setkey(ctx,
+ secret,
+ (int)mbedtls_cipher_info_get_key_bitlen(cipher_info),
+ op);
+
+ if(!ret)
+ ret = mbedtls_cipher_set_iv(ctx, iv,
+ mbedtls_cipher_info_get_iv_size(cipher_info));
+
+ return ret == 0 ? 0 : -1;
+}
+
+int
+_libssh2_mbedtls_cipher_crypt(_libssh2_cipher_ctx *ctx,
+ _libssh2_cipher_type(algo),
+ int encrypt,
+ unsigned char *block,
+ size_t blocklen, int firstlast)
+{
+ int ret;
+ unsigned char *output;
+ size_t osize, olen, finish_olen;
+
+ (void)encrypt;
+ (void)algo;
+ (void)firstlast;
+
+ osize = blocklen + mbedtls_cipher_get_block_size(ctx);
+
+ output = (unsigned char *)mbedtls_calloc(osize, sizeof(char));
+ if(output) {
+ ret = mbedtls_cipher_reset(ctx);
+
+ if(!ret)
+ ret = mbedtls_cipher_update(ctx, block, blocklen, output, &olen);
+
+ if(!ret)
+ ret = mbedtls_cipher_finish(ctx, output + olen, &finish_olen);
+
+ if(!ret) {
+ olen += finish_olen;
+ memcpy(block, output, olen);
+ }
+
+ _libssh2_mbedtls_safe_free(output, osize);
+ }
+ else
+ ret = -1;
+
+ return ret == 0 ? 0 : -1;
+}
+
+void
+_libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx)
+{
+ mbedtls_cipher_free(ctx);
+}
+
+
+int
+_libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx,
+ mbedtls_md_type_t mdtype,
+ const unsigned char *key, size_t keylen)
+{
+ const mbedtls_md_info_t *md_info;
+ int ret, hmac;
+
+ md_info = mbedtls_md_info_from_type(mdtype);
+ if(!md_info)
+ return 0;
+
+ hmac = key ? 1 : 0;
+
+ mbedtls_md_init(ctx);
+ ret = mbedtls_md_setup(ctx, md_info, hmac);
+ if(!ret) {
+ if(hmac)
+ ret = mbedtls_md_hmac_starts(ctx, key, keylen);
+ else
+ ret = mbedtls_md_starts(ctx);
+ }
+
+ return ret == 0 ? 1 : 0;
+}
+
+int
+_libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash)
+{
+ int ret;
+
+ ret = mbedtls_md_finish(ctx, hash);
+ mbedtls_md_free(ctx);
+
+ return ret == 0 ? 1 : 0;
+}
+
+int
+_libssh2_mbedtls_hash(const unsigned char *data, size_t datalen,
+ mbedtls_md_type_t mdtype, unsigned char *hash)
+{
+ const mbedtls_md_info_t *md_info;
+ int ret;
+
+ md_info = mbedtls_md_info_from_type(mdtype);
+ if(!md_info)
+ return 0;
+
+ ret = mbedtls_md(md_info, data, datalen, hash);
+
+ return ret == 0 ? 0 : -1;
+}
+
+int _libssh2_hmac_ctx_init(libssh2_hmac_ctx *ctx)
+{
+ memset(ctx, 0, sizeof(*ctx));
+ return 1;
+}
+
+#if LIBSSH2_MD5
+int _libssh2_hmac_md5_init(libssh2_hmac_ctx *ctx,
+ void *key, size_t keylen)
+{
+ return _libssh2_mbedtls_hash_init(ctx, MBEDTLS_MD_MD5, key, keylen);
+}
+#endif
+
+#if LIBSSH2_HMAC_RIPEMD
+int _libssh2_hmac_ripemd160_init(libssh2_hmac_ctx *ctx,
+ void *key, size_t keylen)
+{
+ return _libssh2_mbedtls_hash_init(ctx, MBEDTLS_MD_RIPEMD160, key, keylen);
+}
+#endif
+
+int _libssh2_hmac_sha1_init(libssh2_hmac_ctx *ctx,
+ void *key, size_t keylen)
+{
+ return _libssh2_mbedtls_hash_init(ctx, MBEDTLS_MD_SHA1, key, keylen);
+}
+
+int _libssh2_hmac_sha256_init(libssh2_hmac_ctx *ctx,
+ void *key, size_t keylen)
+{
+ return _libssh2_mbedtls_hash_init(ctx, MBEDTLS_MD_SHA256, key, keylen);
+}
+
+int _libssh2_hmac_sha512_init(libssh2_hmac_ctx *ctx,
+ void *key, size_t keylen)
+{
+ return _libssh2_mbedtls_hash_init(ctx, MBEDTLS_MD_SHA512, key, keylen);
+}
+
+int _libssh2_hmac_update(libssh2_hmac_ctx *ctx,
+ const void *data, size_t datalen)
+{
+ int ret = mbedtls_md_hmac_update(ctx, data, datalen);
+
+ return ret == 0 ? 1 : 0;
+}
+
+int _libssh2_hmac_final(libssh2_hmac_ctx *ctx, void *data)
+{
+ int ret = mbedtls_md_hmac_finish(ctx, data);
+
+ return ret == 0 ? 1 : 0;
+}
+
+void _libssh2_hmac_cleanup(libssh2_hmac_ctx *ctx)
+{
+ mbedtls_md_free(ctx);
+}
+
+/*******************************************************************/
+/*
+ * mbedTLS backend: BigNumber functions
+ */
+
+_libssh2_bn *
+_libssh2_mbedtls_bignum_init(void)
+{
+ _libssh2_bn *bignum;
+
+ bignum = (_libssh2_bn *)mbedtls_calloc(1, sizeof(_libssh2_bn));
+ if(bignum) {
+ mbedtls_mpi_init(bignum);
+ }
+
+ return bignum;
+}
+
+void
+_libssh2_mbedtls_bignum_free(_libssh2_bn *bn)
+{
+ if(bn) {
+ mbedtls_mpi_free(bn);
+ mbedtls_free(bn);
+ }
+}
+
+static int
+_libssh2_mbedtls_bignum_random(_libssh2_bn *bn, int bits, int top, int bottom)
+{
+ size_t len;
+ int err;
+ size_t i;
+
+ if(!bn || bits <= 0)
+ return -1;
+
+ len = (bits + 7) >> 3;
+ err = mbedtls_mpi_fill_random(bn, len, mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg);
+ if(err)
+ return -1;
+
+ /* Zero unused bits above the most significant bit */
+ for(i = len*8 - 1; (size_t)bits <= i; --i) {
+ err = mbedtls_mpi_set_bit(bn, i, 0);
+ if(err)
+ return -1;
+ }
+
+ /* If `top` is -1, the most significant bit of the random number can be
+ zero. If top is 0, the most significant bit of the random number is
+ set to 1, and if top is 1, the two most significant bits of the number
+ will be set to 1, so that the product of two such random numbers will
+ always have 2*bits length.
+ */
+ if(top >= 0) {
+ for(i = 0; i <= (size_t)top; ++i) {
+ err = mbedtls_mpi_set_bit(bn, bits-i-1, 1);
+ if(err)
+ return -1;
+ }
+ }
+
+ /* make odd by setting first bit in least significant byte */
+ if(bottom) {
+ err = mbedtls_mpi_set_bit(bn, 0, 1);
+ if(err)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*******************************************************************/
+/*
+ * mbedTLS backend: RSA functions
+ */
+
+int
+_libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa,
+ const unsigned char *edata,
+ unsigned long elen,
+ const unsigned char *ndata,
+ unsigned long nlen,
+ const unsigned char *ddata,
+ unsigned long dlen,
+ const unsigned char *pdata,
+ unsigned long plen,
+ const unsigned char *qdata,
+ unsigned long qlen,
+ const unsigned char *e1data,
+ unsigned long e1len,
+ const unsigned char *e2data,
+ unsigned long e2len,
+ const unsigned char *coeffdata,
+ unsigned long coefflen)
+{
+ int ret;
+ libssh2_rsa_ctx *ctx;
+
+ ctx = (libssh2_rsa_ctx *) mbedtls_calloc(1, sizeof(libssh2_rsa_ctx));
+ if(ctx) {
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ mbedtls_rsa_init(ctx);
+#else
+ mbedtls_rsa_init(ctx, MBEDTLS_RSA_PKCS_V15, 0);
+#endif
+ }
+ else
+ return -1;
+
+ /* !checksrc! disable ASSIGNWITHINCONDITION 1 */
+ if((ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(E)),
+ edata, elen)) ||
+ (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(N)),
+ ndata, nlen))) {
+ ret = -1;
+ }
+
+ if(!ret) {
+ ctx->MBEDTLS_PRIVATE(len) =
+ mbedtls_mpi_size(&(ctx->MBEDTLS_PRIVATE(N)));
+ }
+
+ if(!ret && ddata) {
+ /* !checksrc! disable ASSIGNWITHINCONDITION 1 */
+ if((ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(D)),
+ ddata, dlen)) ||
+ (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(P)),
+ pdata, plen)) ||
+ (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(Q)),
+ qdata, qlen)) ||
+ (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(DP)),
+ e1data, e1len)) ||
+ (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(DQ)),
+ e2data, e2len)) ||
+ (ret = mbedtls_mpi_read_binary(&(ctx->MBEDTLS_PRIVATE(QP)),
+ coeffdata, coefflen))) {
+ ret = -1;
+ }
+ ret = mbedtls_rsa_check_privkey(ctx);
+ }
+ else if(!ret) {
+ ret = mbedtls_rsa_check_pubkey(ctx);
+ }
+
+ if(ret && ctx) {
+ _libssh2_mbedtls_rsa_free(ctx);
+ ctx = NULL;
+ }
+ *rsa = ctx;
+ return ret;
+}
+
+int
+_libssh2_mbedtls_rsa_new_private(libssh2_rsa_ctx **rsa,
+ LIBSSH2_SESSION *session,
+ const char *filename,
+ const unsigned char *passphrase)
+{
+ int ret;
+ mbedtls_pk_context pkey;
+ mbedtls_rsa_context *pk_rsa;
+
+ *rsa = (libssh2_rsa_ctx *) LIBSSH2_ALLOC(session, sizeof(libssh2_rsa_ctx));
+ if(!*rsa)
+ return -1;
+
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ mbedtls_rsa_init(*rsa);
+#else
+ mbedtls_rsa_init(*rsa, MBEDTLS_RSA_PKCS_V15, 0);
+#endif
+ mbedtls_pk_init(&pkey);
+
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ ret = mbedtls_pk_parse_keyfile(&pkey, filename, (char *)passphrase,
+ mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg);
+#else
+ ret = mbedtls_pk_parse_keyfile(&pkey, filename, (char *)passphrase);
+#endif
+ if(ret || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) {
+ mbedtls_pk_free(&pkey);
+ mbedtls_rsa_free(*rsa);
+ LIBSSH2_FREE(session, *rsa);
+ *rsa = NULL;
+ return -1;
+ }
+
+ pk_rsa = mbedtls_pk_rsa(pkey);
+ mbedtls_rsa_copy(*rsa, pk_rsa);
+ mbedtls_pk_free(&pkey);
+
+ return 0;
+}
+
+int
+_libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa,
+ LIBSSH2_SESSION *session,
+ const char *filedata,
+ size_t filedata_len,
+ unsigned const char *passphrase)
+{
+ int ret;
+ mbedtls_pk_context pkey;
+ mbedtls_rsa_context *pk_rsa;
+ void *filedata_nullterm;
+ size_t pwd_len;
+
+ *rsa = (libssh2_rsa_ctx *) mbedtls_calloc(1, sizeof(libssh2_rsa_ctx));
+ if(!*rsa)
+ return -1;
+
+ /*
+ mbedtls checks in "mbedtls/pkparse.c:1184" if "key[keylen - 1] != '\0'"
+ private-key from memory will fail if the last byte is not a null byte
+ */
+ filedata_nullterm = mbedtls_calloc(filedata_len + 1, 1);
+ if(!filedata_nullterm) {
+ return -1;
+ }
+ memcpy(filedata_nullterm, filedata, filedata_len);
+
+ mbedtls_pk_init(&pkey);
+
+ pwd_len = passphrase ? strlen((const char *)passphrase) : 0;
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ ret = mbedtls_pk_parse_key(&pkey, (unsigned char *)filedata_nullterm,
+ filedata_len + 1,
+ passphrase, pwd_len,
+ mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg);
+#else
+ ret = mbedtls_pk_parse_key(&pkey, (unsigned char *)filedata_nullterm,
+ filedata_len + 1,
+ passphrase, pwd_len);
+#endif
+ _libssh2_mbedtls_safe_free(filedata_nullterm, filedata_len);
+
+ if(ret || mbedtls_pk_get_type(&pkey) != MBEDTLS_PK_RSA) {
+ mbedtls_pk_free(&pkey);
+ mbedtls_rsa_free(*rsa);
+ LIBSSH2_FREE(session, *rsa);
+ *rsa = NULL;
+ return -1;
+ }
+
+ pk_rsa = mbedtls_pk_rsa(pkey);
+ mbedtls_rsa_copy(*rsa, pk_rsa);
+ mbedtls_pk_free(&pkey);
+
+ return 0;
+}
+
+int
+_libssh2_mbedtls_rsa_sha2_verify(libssh2_rsa_ctx * rsactx,
+ size_t hash_len,
+ const unsigned char *sig,
+ size_t sig_len,
+ const unsigned char *m,
+ size_t m_len)
+{
+ int ret;
+ int md_type;
+ unsigned char *hash;
+
+ if(sig_len < mbedtls_rsa_get_len(rsactx))
+ return -1;
+
+ hash = malloc(hash_len);
+ if(!hash)
+ return -1;
+
+ if(hash_len == SHA_DIGEST_LENGTH) {
+ md_type = MBEDTLS_MD_SHA1;
+ }
+ else if(hash_len == SHA256_DIGEST_LENGTH) {
+ md_type = MBEDTLS_MD_SHA256;
+ }
+ else if(hash_len == SHA512_DIGEST_LENGTH) {
+ md_type = MBEDTLS_MD_SHA512;
+ }
+ else{
+ free(hash);
+ return -1; /* unsupported digest */
+ }
+ ret = _libssh2_mbedtls_hash(m, m_len, md_type, hash);
+
+ if(ret) {
+ free(hash);
+ return -1; /* failure */
+ }
+
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ ret = mbedtls_rsa_pkcs1_verify(rsactx,
+ md_type, (unsigned int)hash_len,
+ hash, sig);
+#else
+ ret = mbedtls_rsa_pkcs1_verify(rsactx, NULL, NULL, MBEDTLS_RSA_PUBLIC,
+ md_type, (unsigned int)hash_len,
+ hash, sig);
+#endif
+ free(hash);
+
+ return (ret == 0) ? 0 : -1;
+}
+
+int
+_libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx * rsactx,
+ const unsigned char *sig,
+ size_t sig_len,
+ const unsigned char *m,
+ size_t m_len)
+{
+ return _libssh2_mbedtls_rsa_sha2_verify(rsactx, SHA_DIGEST_LENGTH,
+ sig, sig_len, m, m_len);
+}
+
+int
+_libssh2_mbedtls_rsa_sha2_sign(LIBSSH2_SESSION *session,
+ libssh2_rsa_ctx *rsa,
+ const unsigned char *hash,
+ size_t hash_len,
+ unsigned char **signature,
+ size_t *signature_len)
+{
+ int ret;
+ unsigned char *sig;
+ size_t sig_len;
+ int md_type;
+
+ sig_len = mbedtls_rsa_get_len(rsa);
+ sig = LIBSSH2_ALLOC(session, sig_len);
+ if(!sig) {
+ return -1;
+ }
+ ret = 0;
+ if(hash_len == SHA_DIGEST_LENGTH) {
+ md_type = MBEDTLS_MD_SHA1;
+ }
+ else if(hash_len == SHA256_DIGEST_LENGTH) {
+ md_type = MBEDTLS_MD_SHA256;
+ }
+ else if(hash_len == SHA512_DIGEST_LENGTH) {
+ md_type = MBEDTLS_MD_SHA512;
+ }
+ else {
+ _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Unsupported hash digest length");
+ ret = -1;
+ }
+ if(ret == 0) {
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ ret = mbedtls_rsa_pkcs1_sign(rsa,
+ mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg,
+ md_type, (unsigned int)hash_len,
+ hash, sig);
+#else
+ ret = mbedtls_rsa_pkcs1_sign(rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE,
+ md_type, (unsigned int)hash_len,
+ hash, sig);
+#endif
+ }
+ if(ret) {
+ LIBSSH2_FREE(session, sig);
+ return -1;
+ }
+
+ *signature = sig;
+ *signature_len = sig_len;
+
+ return (ret == 0) ? 0 : -1;
+}
+
+int
+_libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION * session,
+ libssh2_rsa_ctx * rsactx,
+ const unsigned char *hash,
+ size_t hash_len,
+ unsigned char **signature,
+ size_t *signature_len)
+{
+ return _libssh2_mbedtls_rsa_sha2_sign(session, rsactx, hash, hash_len,
+ signature, signature_len);
+}
+
+void
+_libssh2_mbedtls_rsa_free(libssh2_rsa_ctx *ctx)
+{
+ mbedtls_rsa_free(ctx);
+ mbedtls_free(ctx);
+}
+
+static unsigned char *
+gen_publickey_from_rsa(LIBSSH2_SESSION *session,
+ mbedtls_rsa_context *rsa,
+ size_t *keylen)
+{
+ uint32_t e_bytes, n_bytes;
+ uint32_t len;
+ unsigned char *key;
+ unsigned char *p;
+
+ e_bytes = (uint32_t)mbedtls_mpi_size(&rsa->MBEDTLS_PRIVATE(E));
+ n_bytes = (uint32_t)mbedtls_mpi_size(&rsa->MBEDTLS_PRIVATE(N));
+
+ /* Key form is "ssh-rsa" + e + n. */
+ len = 4 + 7 + 4 + e_bytes + 4 + n_bytes;
+
+ key = LIBSSH2_ALLOC(session, len);
+ if(!key) {
+ return NULL;
+ }
+
+ /* Process key encoding. */
+ p = key;
+
+ _libssh2_htonu32(p, 7); /* Key type. */
+ p += 4;
+ memcpy(p, "ssh-rsa", 7);
+ p += 7;
+
+ _libssh2_htonu32(p, e_bytes);
+ p += 4;
+ mbedtls_mpi_write_binary(&rsa->MBEDTLS_PRIVATE(E), p, e_bytes);
+
+ _libssh2_htonu32(p, n_bytes);
+ p += 4;
+ mbedtls_mpi_write_binary(&rsa->MBEDTLS_PRIVATE(N), p, n_bytes);
+
+ *keylen = (size_t)(p - key);
+ return key;
+}
+
+static int
+_libssh2_mbedtls_pub_priv_key(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ mbedtls_pk_context *pkey)
+{
+ unsigned char *key = NULL, *mth = NULL;
+ size_t keylen = 0, mthlen = 0;
+ int ret;
+ mbedtls_rsa_context *rsa;
+
+ if(mbedtls_pk_get_type(pkey) != MBEDTLS_PK_RSA) {
+ mbedtls_pk_free(pkey);
+ return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Key type not supported");
+ }
+
+ /* write method */
+ mthlen = 7;
+ mth = LIBSSH2_ALLOC(session, mthlen);
+ if(mth) {
+ memcpy(mth, "ssh-rsa", mthlen);
+ }
+ else {
+ ret = -1;
+ }
+
+ rsa = mbedtls_pk_rsa(*pkey);
+ key = gen_publickey_from_rsa(session, rsa, &keylen);
+ if(!key) {
+ ret = -1;
+ }
+
+ /* write output */
+ if(ret) {
+ if(mth)
+ LIBSSH2_FREE(session, mth);
+ if(key)
+ LIBSSH2_FREE(session, key);
+ }
+ else {
+ *method = mth;
+ *method_len = mthlen;
+ *pubkeydata = key;
+ *pubkeydata_len = keylen;
+ }
+
+ return ret;
+}
+
+int
+_libssh2_mbedtls_pub_priv_keyfile(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ const char *privatekey,
+ const char *passphrase)
+{
+ mbedtls_pk_context pkey;
+ char buf[1024];
+ int ret;
+
+ mbedtls_pk_init(&pkey);
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ ret = mbedtls_pk_parse_keyfile(&pkey, privatekey, passphrase,
+ mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg);
+#else
+ ret = mbedtls_pk_parse_keyfile(&pkey, privatekey, passphrase);
+#endif
+ if(ret) {
+ mbedtls_strerror(ret, (char *)buf, sizeof(buf));
+ mbedtls_pk_free(&pkey);
+ return _libssh2_error(session, LIBSSH2_ERROR_FILE, buf);
+ }
+
+ ret = _libssh2_mbedtls_pub_priv_key(session, method, method_len,
+ pubkeydata, pubkeydata_len, &pkey);
+
+ mbedtls_pk_free(&pkey);
+
+ return ret;
+}
+
+int
+_libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ const char *privatekeydata,
+ size_t privatekeydata_len,
+ const char *passphrase)
+{
+ mbedtls_pk_context pkey;
+ char buf[1024];
+ int ret;
+ void *privatekeydata_nullterm;
+ size_t pwd_len;
+
+ /*
+ mbedtls checks in "mbedtls/pkparse.c:1184" if "key[keylen - 1] != '\0'"
+ private-key from memory will fail if the last byte is not a null byte
+ */
+ privatekeydata_nullterm = mbedtls_calloc(privatekeydata_len + 1, 1);
+ if(!privatekeydata_nullterm) {
+ return -1;
+ }
+ memcpy(privatekeydata_nullterm, privatekeydata, privatekeydata_len);
+
+ mbedtls_pk_init(&pkey);
+
+ pwd_len = passphrase ? strlen((const char *)passphrase) : 0;
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ ret = mbedtls_pk_parse_key(&pkey,
+ (unsigned char *)privatekeydata_nullterm,
+ privatekeydata_len + 1,
+ (const unsigned char *)passphrase, pwd_len,
+ mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg);
+#else
+ ret = mbedtls_pk_parse_key(&pkey,
+ (unsigned char *)privatekeydata_nullterm,
+ privatekeydata_len + 1,
+ (const unsigned char *)passphrase, pwd_len);
+#endif
+ _libssh2_mbedtls_safe_free(privatekeydata_nullterm, privatekeydata_len);
+
+ if(ret) {
+ mbedtls_strerror(ret, (char *)buf, sizeof(buf));
+ mbedtls_pk_free(&pkey);
+ return _libssh2_error(session, LIBSSH2_ERROR_FILE, buf);
+ }
+
+ ret = _libssh2_mbedtls_pub_priv_key(session, method, method_len,
+ pubkeydata, pubkeydata_len, &pkey);
+
+ mbedtls_pk_free(&pkey);
+
+ return ret;
+}
+
+int
+_libssh2_mbedtls_sk_pub_keyfilememory(LIBSSH2_SESSION *session,
+ unsigned char **method,
+ size_t *method_len,
+ unsigned char **pubkeydata,
+ size_t *pubkeydata_len,
+ int *algorithm,
+ unsigned char *flags,
+ const char **application,
+ const unsigned char **key_handle,
+ size_t *handle_len,
+ const char *privatekeydata,
+ size_t privatekeydata_len,
+ const char *passphrase)
+{
+ (void)method;
+ (void)method_len;
+ (void)pubkeydata;
+ (void)pubkeydata_len;
+ (void)algorithm;
+ (void)flags;
+ (void)application;
+ (void)key_handle;
+ (void)handle_len;
+ (void)privatekeydata;
+ (void)privatekeydata_len;
+ (void)passphrase;
+
+ return _libssh2_error(session, LIBSSH2_ERROR_FILE,
+ "Unable to extract public SK key from private key file: "
+ "Method unimplemented in mbedTLS backend");
+}
+
+void _libssh2_init_aes_ctr(void)
+{
+ /* no implementation */
+}
+
+
+/*******************************************************************/
+/*
+ * mbedTLS backend: Diffie-Hellman functions
+ */
+
+void
+_libssh2_dh_init(_libssh2_dh_ctx *dhctx)
+{
+ *dhctx = _libssh2_mbedtls_bignum_init(); /* Random from client */
+}
+
+int
+_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
+ _libssh2_bn *g, _libssh2_bn *p, int group_order)
+{
+ /* Generate x and e */
+ _libssh2_mbedtls_bignum_random(*dhctx, group_order * 8 - 1, 0, -1);
+ mbedtls_mpi_exp_mod(public, g, *dhctx, p, NULL);
+ return 0;
+}
+
+int
+_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
+ _libssh2_bn *f, _libssh2_bn *p)
+{
+ /* Compute the shared secret */
+ mbedtls_mpi_exp_mod(secret, f, *dhctx, p, NULL);
+ return 0;
+}
+
+void
+_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx)
+{
+ _libssh2_mbedtls_bignum_free(*dhctx);
+ *dhctx = NULL;
+}
+
+#if LIBSSH2_ECDSA
+
+/*******************************************************************/
+/*
+ * mbedTLS backend: ECDSA functions
+ */
+
+/*
+ * _libssh2_ecdsa_create_key
+ *
+ * Creates a local private key based on input curve
+ * and returns octal value and octal length
+ *
+ */
+
+int
+_libssh2_mbedtls_ecdsa_create_key(LIBSSH2_SESSION *session,
+ _libssh2_ec_key **privkey,
+ unsigned char **pubkey_oct,
+ size_t *pubkey_oct_len,
+ libssh2_curve_type curve)
+{
+ size_t plen = 0;
+
+ *privkey = LIBSSH2_ALLOC(session, sizeof(mbedtls_ecp_keypair));
+
+ if(!*privkey)
+ goto failed;
+
+ mbedtls_ecdsa_init(*privkey);
+
+ if(mbedtls_ecdsa_genkey(*privkey, (mbedtls_ecp_group_id)curve,
+ mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg))
+ goto failed;
+
+ plen = 2 * mbedtls_mpi_size(&(*privkey)->MBEDTLS_PRIVATE(grp).P) + 1;
+ *pubkey_oct = LIBSSH2_ALLOC(session, plen);
+
+ if(!*pubkey_oct)
+ goto failed;
+
+ if(mbedtls_ecp_point_write_binary(&(*privkey)->MBEDTLS_PRIVATE(grp),
+ &(*privkey)->MBEDTLS_PRIVATE(Q),
+ MBEDTLS_ECP_PF_UNCOMPRESSED,
+ pubkey_oct_len, *pubkey_oct, plen) == 0)
+ return 0;
+
+failed:
+
+ _libssh2_mbedtls_ecdsa_free(*privkey);
+ _libssh2_mbedtls_safe_free(*pubkey_oct, plen);
+ *privkey = NULL;
+
+ return -1;
+}
+
+/* _libssh2_ecdsa_curve_name_with_octal_new
+ *
+ * Creates a new public key given an octal string, length and type
+ *
+ */
+
+int
+_libssh2_mbedtls_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx **ctx,
+ const unsigned char *k,
+ size_t k_len,
+ libssh2_curve_type curve)
+{
+ *ctx = mbedtls_calloc(1, sizeof(mbedtls_ecp_keypair));
+
+ if(!*ctx)
+ goto failed;
+
+ mbedtls_ecdsa_init(*ctx);
+
+ if(mbedtls_ecp_group_load(&(*ctx)->MBEDTLS_PRIVATE(grp),
+ (mbedtls_ecp_group_id)curve))
+ goto failed;
+
+ if(mbedtls_ecp_point_read_binary(&(*ctx)->MBEDTLS_PRIVATE(grp),
+ &(*ctx)->MBEDTLS_PRIVATE(Q),
+ k, k_len))
+ goto failed;
+
+ if(mbedtls_ecp_check_pubkey(&(*ctx)->MBEDTLS_PRIVATE(grp),
+ &(*ctx)->MBEDTLS_PRIVATE(Q)) == 0)
+ return 0;
+
+failed:
+
+ _libssh2_mbedtls_ecdsa_free(*ctx);
+ *ctx = NULL;
+
+ return -1;
+}
+
+/* _libssh2_ecdh_gen_k
+ *
+ * Computes the shared secret K given a local private key,
+ * remote public key and length
+ */
+
+int
+_libssh2_mbedtls_ecdh_gen_k(_libssh2_bn **k,
+ _libssh2_ec_key *privkey,
+ const unsigned char *server_pubkey,
+ size_t server_pubkey_len)
+{
+ mbedtls_ecp_point pubkey;
+ int rc = 0;
+
+ if(!*k)
+ return -1;
+
+ mbedtls_ecp_point_init(&pubkey);
+
+ if(mbedtls_ecp_point_read_binary(&privkey->MBEDTLS_PRIVATE(grp),
+ &pubkey,
+ server_pubkey, server_pubkey_len)) {
+ rc = -1;
+ goto cleanup;
+ }
+
+ if(mbedtls_ecdh_compute_shared(&privkey->MBEDTLS_PRIVATE(grp), *k,
+ &pubkey,
+ &privkey->MBEDTLS_PRIVATE(d),
+ mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg)) {
+ rc = -1;
+ goto cleanup;
+ }
+
+ if(mbedtls_ecp_check_privkey(&privkey->MBEDTLS_PRIVATE(grp), *k))
+ rc = -1;
+
+cleanup:
+
+ mbedtls_ecp_point_free(&pubkey);
+
+ return rc;
+}
+
+#define LIBSSH2_MBEDTLS_ECDSA_VERIFY(digest_type) \
+ do { \
+ unsigned char hsh[SHA##digest_type##_DIGEST_LENGTH]; \
+ \
+ if(libssh2_sha##digest_type(m, m_len, hsh) == 0) { \
+ rc = mbedtls_ecdsa_verify(&ctx->MBEDTLS_PRIVATE(grp), hsh, \
+ SHA##digest_type##_DIGEST_LENGTH, \
+ &ctx->MBEDTLS_PRIVATE(Q), &pr, &ps); \
+ } \
+ } while(0)
+
+/* _libssh2_ecdsa_verify
+ *
+ * Verifies the ECDSA signature of a hashed message
+ *
+ */
+
+int
+_libssh2_mbedtls_ecdsa_verify(libssh2_ecdsa_ctx *ctx,
+ const unsigned char *r, size_t r_len,
+ const unsigned char *s, size_t s_len,
+ const unsigned char *m, size_t m_len)
+{
+ mbedtls_mpi pr, ps;
+ int rc = -1;
+
+ mbedtls_mpi_init(&pr);
+ mbedtls_mpi_init(&ps);
+
+ if(mbedtls_mpi_read_binary(&pr, r, r_len))
+ goto cleanup;
+
+ if(mbedtls_mpi_read_binary(&ps, s, s_len))
+ goto cleanup;
+
+ switch(_libssh2_ecdsa_get_curve_type(ctx)) {
+ case LIBSSH2_EC_CURVE_NISTP256:
+ LIBSSH2_MBEDTLS_ECDSA_VERIFY(256);
+ break;
+ case LIBSSH2_EC_CURVE_NISTP384:
+ LIBSSH2_MBEDTLS_ECDSA_VERIFY(384);
+ break;
+ case LIBSSH2_EC_CURVE_NISTP521:
+ LIBSSH2_MBEDTLS_ECDSA_VERIFY(512);
+ break;
+ default:
+ rc = -1;
+ }
+
+cleanup:
+
+ mbedtls_mpi_free(&pr);
+ mbedtls_mpi_free(&ps);
+
+ return (rc == 0) ? 0 : -1;
+}
+
+static int
+_libssh2_mbedtls_parse_eckey(libssh2_ecdsa_ctx **ctx,
+ mbedtls_pk_context *pkey,
+ LIBSSH2_SESSION *session,
+ const unsigned char *data,
+ size_t data_len,
+ const unsigned char *pwd)
+{
+ size_t pwd_len;
+
+ pwd_len = pwd ? strlen((const char *) pwd) : 0;
+
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ if(mbedtls_pk_parse_key(pkey, data, data_len, pwd, pwd_len,
+ mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg))
+
+ goto failed;
+#else
+ if(mbedtls_pk_parse_key(pkey, data, data_len, pwd, pwd_len))
+ goto failed;
+#endif
+
+ if(mbedtls_pk_get_type(pkey) != MBEDTLS_PK_ECKEY)
+ goto failed;
+
+ *ctx = LIBSSH2_ALLOC(session, sizeof(libssh2_ecdsa_ctx));
+
+ if(!*ctx)
+ goto failed;
+
+ mbedtls_ecdsa_init(*ctx);
+
+ if(mbedtls_ecdsa_from_keypair(*ctx, mbedtls_pk_ec(*pkey)) == 0)
+ return 0;
+
+failed:
+
+ _libssh2_mbedtls_ecdsa_free(*ctx);
+ *ctx = NULL;
+
+ return -1;
+}
+
+static int
+_libssh2_mbedtls_parse_openssh_key(libssh2_ecdsa_ctx **ctx,
+ LIBSSH2_SESSION *session,
+ const unsigned char *data,
+ size_t data_len,
+ const unsigned char *pwd)
+{
+ libssh2_curve_type type;
+ unsigned char *name = NULL;
+ struct string_buf *decrypted = NULL;
+ size_t curvelen, exponentlen, pointlen;
+ unsigned char *curve, *exponent, *point_buf;
+
+ if(_libssh2_openssh_pem_parse_memory(session, pwd,
+ (const char *)data, data_len,
+ &decrypted))
+ goto failed;
+
+ if(_libssh2_get_string(decrypted, &name, NULL))
+ goto failed;
+
+ if(_libssh2_mbedtls_ecdsa_curve_type_from_name((const char *)name,
+ &type))
+ goto failed;
+
+ if(_libssh2_get_string(decrypted, &curve, &curvelen))
+ goto failed;
+
+ if(_libssh2_get_string(decrypted, &point_buf, &pointlen))
+ goto failed;
+
+ if(_libssh2_get_bignum_bytes(decrypted, &exponent, &exponentlen))
+ goto failed;
+
+ *ctx = LIBSSH2_ALLOC(session, sizeof(libssh2_ecdsa_ctx));
+
+ if(!*ctx)
+ goto failed;
+
+ mbedtls_ecdsa_init(*ctx);
+
+ if(mbedtls_ecp_group_load(&(*ctx)->MBEDTLS_PRIVATE(grp),
+ (mbedtls_ecp_group_id)type))
+ goto failed;
+
+ if(mbedtls_mpi_read_binary(&(*ctx)->MBEDTLS_PRIVATE(d),
+ exponent, exponentlen))
+ goto failed;
+
+ if(mbedtls_ecp_mul(&(*ctx)->MBEDTLS_PRIVATE(grp),
+ &(*ctx)->MBEDTLS_PRIVATE(Q),
+ &(*ctx)->MBEDTLS_PRIVATE(d),
+ &(*ctx)->MBEDTLS_PRIVATE(grp).G,
+ mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg))
+ goto failed;
+
+ if(mbedtls_ecp_check_privkey(&(*ctx)->MBEDTLS_PRIVATE(grp),
+ &(*ctx)->MBEDTLS_PRIVATE(d)) == 0)
+ goto cleanup;
+
+failed:
+
+ _libssh2_mbedtls_ecdsa_free(*ctx);
+ *ctx = NULL;
+
+cleanup:
+
+ if(decrypted) {
+ _libssh2_string_buf_free(session, decrypted);
+ }
+
+ return *ctx ? 0 : -1;
+}
+
+/* Force-expose internal mbedTLS function */
+#if MBEDTLS_VERSION_NUMBER >= 0x03060000
+int mbedtls_pk_load_file(const char *path, unsigned char **buf, size_t *n);
+#endif
+
+/* _libssh2_ecdsa_new_private
+ *
+ * Creates a new private key given a file path and password
+ *
+ */
+
+int
+_libssh2_mbedtls_ecdsa_new_private(libssh2_ecdsa_ctx **ctx,
+ LIBSSH2_SESSION *session,
+ const char *filename,
+ const unsigned char *pwd)
+{
+ mbedtls_pk_context pkey;
+ unsigned char *data = NULL;
+ size_t data_len = 0;
+
+ mbedtls_pk_init(&pkey);
+
+ /* FIXME: Reimplement this functionality via a public API. */
+ if(mbedtls_pk_load_file(filename, &data, &data_len))
+ goto cleanup;
+
+ if(_libssh2_mbedtls_parse_eckey(ctx, &pkey, session,
+ data, data_len, pwd) == 0)
+ goto cleanup;
+
+ _libssh2_mbedtls_parse_openssh_key(ctx, session, data, data_len, pwd);
+
+cleanup:
+
+ mbedtls_pk_free(&pkey);
+
+ _libssh2_mbedtls_safe_free(data, data_len);
+
+ return *ctx ? 0 : -1;
+}
+
+/* _libssh2_ecdsa_new_private
+ *
+ * Creates a new private key given a file data and password
+ *
+ */
+
+int
+_libssh2_mbedtls_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx **ctx,
+ LIBSSH2_SESSION *session,
+ const char *data,
+ size_t data_len,
+ const unsigned char *pwd)
+{
+ unsigned char *ntdata;
+ mbedtls_pk_context pkey;
+
+ mbedtls_pk_init(&pkey);
+
+ ntdata = LIBSSH2_ALLOC(session, data_len + 1);
+
+ if(!ntdata)
+ goto cleanup;
+
+ memcpy(ntdata, data, data_len);
+
+ if(_libssh2_mbedtls_parse_eckey(ctx, &pkey, session,
+ ntdata, data_len + 1, pwd) == 0)
+ goto cleanup;
+
+ _libssh2_mbedtls_parse_openssh_key(ctx, session,
+ ntdata, data_len + 1, pwd);
+
+cleanup:
+
+ mbedtls_pk_free(&pkey);
+
+ _libssh2_mbedtls_safe_free(ntdata, data_len);
+
+ return *ctx ? 0 : -1;
+}
+
+static unsigned char *
+_libssh2_mbedtls_mpi_write_binary(unsigned char *buf,
+ const mbedtls_mpi *mpi,
+ size_t bytes)
+{
+ unsigned char *p = buf;
+ uint32_t size = (uint32_t)bytes;
+
+ if(sizeof(&p) / sizeof(p[0]) < 4) {
+ goto done;
+ }
+
+ p += 4;
+ *p = 0;
+
+ if(size > 0) {
+ mbedtls_mpi_write_binary(mpi, p + 1, size - 1);
+ }
+
+ if(size > 0 && !(*(p + 1) & 0x80)) {
+ memmove(p, p + 1, --size);
+ }
+
+ _libssh2_htonu32(p - 4, size);
+
+done:
+
+ return p + size;
+}
+
+/* _libssh2_ecdsa_sign
+ *
+ * Computes the ECDSA signature of a previously-hashed message
+ *
+ */
+
+int
+_libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session,
+ libssh2_ecdsa_ctx *ctx,
+ const unsigned char *hash,
+ size_t hash_len,
+ unsigned char **sign,
+ size_t *sign_len)
+{
+ size_t r_len, s_len, tmp_sign_len = 0;
+ unsigned char *sp, *tmp_sign = NULL;
+ mbedtls_mpi pr, ps;
+
+ mbedtls_mpi_init(&pr);
+ mbedtls_mpi_init(&ps);
+
+ if(mbedtls_ecdsa_sign(&ctx->MBEDTLS_PRIVATE(grp), &pr, &ps,
+ &ctx->MBEDTLS_PRIVATE(d),
+ hash, hash_len,
+ mbedtls_ctr_drbg_random,
+ &_libssh2_mbedtls_ctr_drbg))
+ goto cleanup;
+
+ r_len = mbedtls_mpi_size(&pr) + 1;
+ s_len = mbedtls_mpi_size(&ps) + 1;
+ tmp_sign_len = r_len + s_len + 8;
+
+ tmp_sign = LIBSSH2_CALLOC(session, tmp_sign_len);
+
+ if(!tmp_sign)
+ goto cleanup;
+
+ sp = tmp_sign;
+ sp = _libssh2_mbedtls_mpi_write_binary(sp, &pr, r_len);
+ sp = _libssh2_mbedtls_mpi_write_binary(sp, &ps, s_len);
+
+ *sign_len = (size_t)(sp - tmp_sign);
+
+ *sign = LIBSSH2_CALLOC(session, *sign_len);
+
+ if(!*sign)
+ goto cleanup;
+
+ memcpy(*sign, tmp_sign, *sign_len);
+
+cleanup:
+
+ mbedtls_mpi_free(&pr);
+ mbedtls_mpi_free(&ps);
+
+ _libssh2_mbedtls_safe_free(tmp_sign, tmp_sign_len);
+
+ return *sign ? 0 : -1;
+}
+
+/* _libssh2_ecdsa_get_curve_type
+ *
+ * returns key curve type that maps to libssh2_curve_type
+ *
+ */
+
+libssh2_curve_type
+_libssh2_mbedtls_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ctx)
+{
+ return (libssh2_curve_type) ctx->MBEDTLS_PRIVATE(grp).id;
+}
+
+/* _libssh2_ecdsa_curve_type_from_name
+ *
+ * returns 0 for success, key curve type that maps to libssh2_curve_type
+ *
+ */
+
+int
+_libssh2_mbedtls_ecdsa_curve_type_from_name(const char *name,
+ libssh2_curve_type *out_type)
+{
+ int ret = 0;
+ libssh2_curve_type type;
+
+ if(!name || strlen(name) != 19)
+ return -1;
+
+ if(strcmp(name, "ecdsa-sha2-nistp256") == 0)
+ type = LIBSSH2_EC_CURVE_NISTP256;
+ else if(strcmp(name, "ecdsa-sha2-nistp384") == 0)
+ type = LIBSSH2_EC_CURVE_NISTP384;
+ else if(strcmp(name, "ecdsa-sha2-nistp521") == 0)
+ type = LIBSSH2_EC_CURVE_NISTP521;
+ else {
+ ret = -1;
+ }
+
+ if(ret == 0 && out_type) {
+ *out_type = type;
+ }
+
+ return ret;
+}
+
+void
+_libssh2_mbedtls_ecdsa_free(libssh2_ecdsa_ctx *ctx)
+{
+ mbedtls_ecdsa_free(ctx);
+ mbedtls_free(ctx);
+}
+#endif /* LIBSSH2_ECDSA */
+
+
+/* _libssh2_supported_key_sign_algorithms
+ *
+ * Return supported key hash algo upgrades, see crypto.h
+ *
+ */
+
+const char *
+_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
+ unsigned char *key_method,
+ size_t key_method_len)
+{
+ (void)session;
+
+#if LIBSSH2_RSA_SHA2
+ if(key_method_len == 7 &&
+ memcmp(key_method, "ssh-rsa", key_method_len) == 0) {
+ return "rsa-sha2-512,rsa-sha2-256"
+#if LIBSSH2_RSA_SHA1
+ ",ssh-rsa"
+#endif
+ ;
+ }
+#endif
+
+ return NULL;
+}
+
+#endif /* LIBSSH2_CRYPTO_C */