diff --git a/src/openssl.c b/src/openssl.c index c190bbfa..f6764c3c 100644 --- a/src/openssl.c +++ b/src/openssl.c @@ -92,6 +92,20 @@ write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes) } #endif +static inline void +_libssh2_swap_bytes(unsigned char *buf, unsigned long len) +{ +#if !defined(WORDS_BIGENDIAN) || !WORDS_BIGENDIAN + unsigned long i, j; + unsigned char temp; + for(i = 0, j = len - 1; i < j; i++, j--) { + temp = buf[i]; + buf[i] = buf[j]; + buf[j] = temp; + } +#endif +} + int _libssh2_openssl_random(void *buf, size_t len) { @@ -121,6 +135,76 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, unsigned long e2len, const unsigned char *coeffdata, unsigned long coefflen) { +#ifdef USE_OPENSSL_3 + int ret = 0; + EVP_PKEY_CTX *ctx; + OSSL_PARAM params[4]; + int param_num = 0; + unsigned char *nbuf = NULL; + unsigned char *ebuf = NULL; + unsigned char *dbuf = NULL; + + (void)pdata; + (void)plen; + (void)qdata; + (void)qlen; + (void)e1data; + (void)e1len; + (void)e2data; + (void)e2len; + (void)coeffdata; + (void)coefflen; + + if(ndata && nlen > 0) { + nbuf = OPENSSL_malloc(nlen); + + if(nbuf) { + memcpy(nbuf, ndata, nlen); + _libssh2_swap_bytes(nbuf, nlen); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_N, nbuf, nlen); + } + } + + if(edata && elen > 0) { + ebuf = OPENSSL_malloc(elen); + if(ebuf) { + memcpy(ebuf, edata, elen); + _libssh2_swap_bytes(ebuf, elen); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_E, ebuf, elen); + } + } + + if(ddata && dlen > 0) { + dbuf = OPENSSL_malloc(dlen); + if(dbuf) { + memcpy(dbuf, ddata, dlen); + _libssh2_swap_bytes(dbuf, dlen); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_D, dbuf, dlen); + } + } + + params[param_num] = OSSL_PARAM_construct_end(); + + *rsa = NULL; + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); + + if(EVP_PKEY_fromdata_init(ctx) > 0) { + ret = EVP_PKEY_fromdata(ctx, rsa, EVP_PKEY_KEYPAIR, params); + } + if(nbuf) + OPENSSL_clear_free(nbuf, nlen); + + if(ebuf) + OPENSSL_clear_free(ebuf, elen); + + if(dbuf) + OPENSSL_clear_free(dbuf, dlen); + + return (ret == 1) ? 0 : -1; +#else BIGNUM * e; BIGNUM * n; BIGNUM * d = 0; @@ -180,6 +264,8 @@ _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, (*rsa)->iqmp = iqmp; #endif return 0; + +#endif /* USE_OPENSSL_3 */ } int @@ -189,6 +275,11 @@ _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsactx, size_t sig_len, const unsigned char *m, size_t m_len) { +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = NULL; + const EVP_MD *md = NULL; +#endif + int ret; int nid_type; unsigned char *hash = malloc(hash_len); @@ -221,9 +312,37 @@ _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsactx, return -1; /* failure */ } +#ifdef USE_OPENSSL_3 + ctx = EVP_PKEY_CTX_new(rsactx, NULL); + + if(nid_type == NID_sha1) { + md = EVP_sha1(); + } + else if(nid_type == NID_sha256) { + md = EVP_sha256(); + } + else if(nid_type == NID_sha512) { + md = EVP_sha512(); + } + + if(ctx && md) { + if(EVP_PKEY_verify_init(ctx) > 0 && + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) > 0 && + EVP_PKEY_CTX_set_signature_md(ctx, md) > 0) { + ret = EVP_PKEY_verify(ctx, sig, sig_len, hash, hash_len); + } + } + + if(ctx) { + EVP_PKEY_CTX_free(ctx); + } + +#else + ret = RSA_verify(nid_type, hash, (unsigned int) hash_len, (unsigned char *) sig, (unsigned int) sig_len, rsactx); +#endif free(hash); @@ -256,6 +375,97 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, unsigned long y_len, const unsigned char *x, unsigned long x_len) { +#ifdef USE_OPENSSL_3 + int ret = 0; + EVP_PKEY_CTX *ctx = NULL; + OSSL_PARAM params[6]; + int param_num = 0; + unsigned char *p_buf = NULL; + unsigned char *q_buf = NULL; + unsigned char *g_buf = NULL; + unsigned char *y_buf = NULL; + unsigned char *x_buf = NULL; + + if(p && p_len > 0) { + p_buf = OPENSSL_malloc(p_len); + + if(p_buf) { + memcpy(p_buf, p, p_len); + _libssh2_swap_bytes(p_buf, p_len); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_FFC_P, p_buf, p_len); + } + } + + if(q && q_len > 0) { + q_buf = OPENSSL_malloc(q_len); + + if(q_buf) { + memcpy(q_buf, q, q_len); + _libssh2_swap_bytes(q_buf, q_len); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_FFC_Q, q_buf, q_len); + } + } + + if(g && g_len > 0) { + g_buf = OPENSSL_malloc(g_len); + + if(g_buf) { + memcpy(g_buf, g, g_len); + _libssh2_swap_bytes(g_buf, g_len); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_FFC_G, g_buf, g_len); + } + } + + if(y && y_len > 0) { + y_buf = OPENSSL_malloc(y_len); + + if(y_buf) { + memcpy(y_buf, y, y_len); + _libssh2_swap_bytes(y_buf, y_len); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_PUB_KEY, y_buf, y_len); + } + } + + if(x && x_len > 0) { + x_buf = OPENSSL_malloc(x_len); + + if(x_buf) { + memcpy(x_buf, x, x_len); + _libssh2_swap_bytes(x_buf, x_len); + params[param_num++] = + OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_PRIV_KEY, + x_buf, x_len); + } + } + + params[param_num] = OSSL_PARAM_construct_end(); + + *dsactx = NULL; + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL); + + if(EVP_PKEY_fromdata_init(ctx) > 0) { + ret = EVP_PKEY_fromdata(ctx, dsactx, EVP_PKEY_KEYPAIR, params); + } + + if(p_buf) + OPENSSL_clear_free(p_buf, p_len); + if(q_buf) + OPENSSL_clear_free(q_buf, q_len); + if(g_buf) + OPENSSL_clear_free(g_buf, g_len); + if(x_buf) + OPENSSL_clear_free(x_buf, x_len); + if(y_buf) + OPENSSL_clear_free(y_buf, y_len); + + return (ret == 1) ? 0 : -1; + +#else + BIGNUM * p_bn; BIGNUM * q_bn; BIGNUM * g_bn; @@ -296,6 +506,8 @@ _libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, (*dsactx)->priv_key = priv_key; #endif return 0; + +#endif /* USE_OPENSSL_3 */ } int @@ -303,6 +515,12 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, const unsigned char *sig, const unsigned char *m, size_t m_len) { +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = NULL; + unsigned char *der = NULL; + int der_len = 0; +#endif + unsigned char hash[SHA_DIGEST_LENGTH]; DSA_SIG * dsasig; BIGNUM * r; @@ -321,10 +539,32 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, dsasig->r = r; dsasig->s = s; #endif + +#ifdef USE_OPENSSL_3 + ctx = EVP_PKEY_CTX_new(dsactx, NULL); + der_len = i2d_DSA_SIG(dsasig, &der); + + if(ctx && !_libssh2_sha1(m, m_len, hash)) { + /* _libssh2_sha1() succeeded */ + if(EVP_PKEY_verify_init(ctx) > 0) { + ret = EVP_PKEY_verify(ctx, der, der_len, hash, SHA_DIGEST_LENGTH); + } + } + + if(ctx) { + EVP_PKEY_CTX_free(ctx); + } + + if(der) { + OPENSSL_clear_free(der, der_len); + } +#else if(!_libssh2_sha1(m, m_len, hash)) /* _libssh2_sha1() succeeded */ ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, dsasig, dsactx); +#endif + DSA_SIG_free(dsasig); return (ret == 1) ? 0 : -1; @@ -342,8 +582,25 @@ _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, libssh2_curve_type _libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx) { +#ifdef USE_OPENSSL_3 + int bits = 0; + EVP_PKEY_get_int_param(ec_ctx, OSSL_PKEY_PARAM_BITS, &bits); + + if(bits == 256) { + return LIBSSH2_EC_CURVE_NISTP256; + } + else if(bits == 384) { + return LIBSSH2_EC_CURVE_NISTP384; + } + else if(bits == 521) { + return LIBSSH2_EC_CURVE_NISTP521; + } + + return LIBSSH2_EC_CURVE_NISTP256; +#else const EC_GROUP *group = EC_KEY_get0_group(ec_ctx); return EC_GROUP_get_curve_name(group); +#endif } /* _libssh2_ecdsa_curve_type_from_name @@ -390,11 +647,54 @@ _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ec_ctx, size_t k_len, libssh2_curve_type curve) { int ret = 0; - const EC_GROUP *ec_group = NULL; EC_KEY *ec_key = EC_KEY_new_by_curve_name(curve); - EC_POINT *point = NULL; if(ec_key) { +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + const char *n = EC_curve_nid2nist(curve); + char *group_name = NULL; + unsigned char *data = NULL; + + if(n) { + group_name = OPENSSL_zalloc(strlen(n) + 1); + } + + if(k_len > 0) { + data = OPENSSL_malloc(k_len); + } + + if(group_name && data) { + OSSL_PARAM params[3] = { 0 }; + + memcpy(group_name, n, strlen(n)); + memcpy(data, k, k_len); + + params[0] = + OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + group_name, 0); + + params[1] = + OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, + data, k_len); + + params[2] = OSSL_PARAM_construct_end(); + + if(EVP_PKEY_fromdata_init(ctx) > 0) { + ret = EVP_PKEY_fromdata(ctx, ec_ctx, EVP_PKEY_PUBLIC_KEY, + params); + } + + if(group_name) + OPENSSL_clear_free(group_name, strlen(n)); + + if(data) + OPENSSL_clear_free(data, k_len); + } +#else + const EC_GROUP *ec_group = NULL; + EC_POINT *point = NULL; + ec_group = EC_KEY_get0_group(ec_key); point = EC_POINT_new(ec_group); ret = EC_POINT_oct2point(ec_group, point, k, k_len, NULL); @@ -405,11 +705,24 @@ _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ec_ctx, if(ec_ctx) *ec_ctx = ec_key; +#endif } return (ret == 1) ? 0 : -1; } +#ifdef USE_OPENSSL_3 +#define LIBSSH2_ECDSA_VERIFY(digest_type) \ + do { \ + unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ + libssh2_sha##digest_type(m, m_len, hash); \ + ret = EVP_PKEY_verify_init(ctx); \ + if(ret > 0) { \ + ret = EVP_PKEY_verify(ctx, der, der_len, hash, \ + SHA##digest_type##_DIGEST_LENGTH); \ + } \ + } while(0) +#else #define LIBSSH2_ECDSA_VERIFY(digest_type) \ do { \ unsigned char hash[SHA##digest_type##_DIGEST_LENGTH]; \ @@ -417,16 +730,24 @@ _libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ec_ctx, ret = ECDSA_do_verify(hash, SHA##digest_type##_DIGEST_LENGTH, \ ecdsa_sig, ec_key); \ } while(0) +#endif int -_libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx, +_libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ecdsa_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) { int ret = 0; - EC_KEY *ec_key = (EC_KEY*)ctx; - libssh2_curve_type type = _libssh2_ecdsa_get_curve_type(ec_key); + libssh2_curve_type type = _libssh2_ecdsa_get_curve_type(ecdsa_ctx); + +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = NULL; + unsigned char *der = NULL; + int der_len = 0; +#else + EC_KEY *ec_key = (EC_KEY*)ecdsa_ctx; +#endif #ifdef HAVE_OPAQUE_STRUCTS ECDSA_SIG *ecdsa_sig = ECDSA_SIG_new(); @@ -445,6 +766,11 @@ _libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx, BN_bin2bn(s, (int) s_len, ecdsa_sig_.s); #endif +#ifdef USE_OPENSSL_3 + ctx = EVP_PKEY_CTX_new(ecdsa_ctx, NULL); + der_len = i2d_ECDSA_SIG(ecdsa_sig, &der); +#endif + if(type == LIBSSH2_EC_CURVE_NISTP256) { LIBSSH2_ECDSA_VERIFY(256); } @@ -565,8 +891,7 @@ _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, #endif } -#if (defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3) || \ - defined(LIBSSH2_WOLFSSL) +#if defined(USE_OPENSSL_3) || defined(LIBSSH2_WOLFSSL) if(ret != -1) #else if(ret >= 1) @@ -714,8 +1039,13 @@ _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_rsa = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_rsa = (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey; +#endif _libssh2_init_if_needed(); @@ -731,21 +1061,37 @@ _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa, } static unsigned char * -gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa, +gen_publickey_from_rsa(LIBSSH2_SESSION *session, libssh2_rsa_ctx *rsa, size_t *key_len) { int e_bytes, n_bytes; unsigned long len; unsigned char *key; unsigned char *p; + +#ifdef USE_OPENSSL_3 + BIGNUM * e = NULL; + BIGNUM * n = NULL; + + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_E, &e); + EVP_PKEY_get_bn_param(rsa, OSSL_PKEY_PARAM_RSA_N, &n); +#else const BIGNUM * e; const BIGNUM * n; -#ifdef HAVE_OPAQUE_STRUCTS +#if defined(HAVE_OPAQUE_STRUCTS) + e = NULL; + n = NULL; + RSA_get0_key(rsa, &n, &e, NULL); #else e = rsa->e; n = rsa->n; #endif +#endif + if(!e || !n) { + return NULL; + } + e_bytes = BN_num_bytes(e) + 1; n_bytes = BN_num_bytes(n) + 1; @@ -780,7 +1126,7 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, size_t *pubkeydata_len, EVP_PKEY *pk) { - RSA* rsa = NULL; + libssh2_rsa_ctx* rsa = NULL; unsigned char *key; unsigned char *method_buf = NULL; size_t key_len; @@ -789,7 +1135,11 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, LIBSSH2_TRACE_AUTH, "Computing public key from RSA private key envelope")); +#ifdef USE_OPENSSL_3 + rsa = pk; +#else rsa = EVP_PKEY_get1_RSA(pk); +#endif if(!rsa) { /* Assume memory allocation error... what else could it be ? */ goto __alloc_error; @@ -804,7 +1154,9 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, if(!key) { goto __alloc_error; } +#ifndef USE_OPENSSL_3 RSA_free(rsa); +#endif memcpy(method_buf, "ssh-rsa", 7); *method = method_buf; @@ -814,9 +1166,11 @@ gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, return 0; __alloc_error: +#ifndef USE_OPENSSL_3 if(rsa) { RSA_free(rsa); } +#endif if(method_buf) { LIBSSH2_FREE(session, method_buf); } @@ -826,7 +1180,8 @@ __alloc_error: "Unable to allocate memory for private key data"); } -static int _libssh2_rsa_new_additional_parameters(RSA *rsa) +#ifndef USE_OPENSSL_3 +static int _libssh2_rsa_new_additional_parameters(libssh2_rsa_ctx *rsa) { BN_CTX *ctx = NULL; BIGNUM *aux = NULL; @@ -897,6 +1252,7 @@ out: return rc; } +#endif /* ndef USE_OPENSSL_3 */ static int gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, @@ -910,7 +1266,7 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, int rc = 0; size_t nlen, elen, dlen, plen, qlen, coefflen, commentlen; unsigned char *n, *e, *d, *p, *q, *coeff, *comment; - RSA *rsa = NULL; + libssh2_rsa_ctx *rsa = NULL; _libssh2_debug((session, LIBSSH2_TRACE_AUTH, @@ -975,32 +1331,40 @@ gen_publickey_from_rsa_openssh_priv_data(LIBSSH2_SESSION *session, goto fail; } +#ifndef USE_OPENSSL_3 if(rsa) rc = _libssh2_rsa_new_additional_parameters(rsa); +#endif if(rsa && pubkeydata && method) { +#ifdef USE_OPENSSL_3 + EVP_PKEY *pk = rsa; +#else EVP_PKEY *pk = EVP_PKEY_new(); EVP_PKEY_set1_RSA(pk, rsa); +#endif rc = gen_publickey_from_rsa_evp(session, method, method_len, pubkeydata, pubkeydata_len, pk); +#ifndef USE_OPENSSL_3 if(pk) EVP_PKEY_free(pk); +#endif } if(rsa_ctx) *rsa_ctx = rsa; else - RSA_free(rsa); + _libssh2_rsa_free(rsa); return rc; fail: if(rsa) - RSA_free(rsa); + _libssh2_rsa_free(rsa); return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -1070,8 +1434,13 @@ _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_rsa = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_rsa = (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey; +#endif _libssh2_init_if_needed(); @@ -1096,8 +1465,13 @@ _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa, { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_dsa = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_dsa = (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey; +#endif _libssh2_init_if_needed(); @@ -1237,7 +1611,7 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session, int rc = 0; size_t plen, qlen, glen, pub_len, priv_len; unsigned char *p, *q, *g, *pub_key, *priv_key; - DSA *dsa = NULL; + libssh2_dsa_ctx *dsa = NULL; _libssh2_debug((session, LIBSSH2_TRACE_AUTH, @@ -1287,28 +1661,34 @@ gen_publickey_from_dsa_openssh_priv_data(LIBSSH2_SESSION *session, } if(dsa && pubkeydata && method) { +#ifdef USE_OPENSSL_3 + EVP_PKEY *pk = dsa; +#else EVP_PKEY *pk = EVP_PKEY_new(); EVP_PKEY_set1_DSA(pk, dsa); +#endif rc = gen_publickey_from_dsa_evp(session, method, method_len, pubkeydata, pubkeydata_len, pk); +#ifndef USE_OPENSSL_3 if(pk) EVP_PKEY_free(pk); +#endif } if(dsa_ctx) *dsa_ctx = dsa; else - DSA_free(dsa); + _libssh2_dsa_free(dsa); return rc; fail: if(dsa) - DSA_free(dsa); + _libssh2_dsa_free(dsa); return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, @@ -1378,8 +1758,13 @@ _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_dsa = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_dsa = (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey; +#endif _libssh2_init_if_needed(); @@ -1406,8 +1791,13 @@ _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx, { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_ec = + (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; +#endif _libssh2_init_if_needed(); @@ -2127,17 +2517,57 @@ _libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session, size_t hash_len, unsigned char **signature, size_t *signature_len) { - int ret; - unsigned char *sig; - unsigned int sig_len; + int ret = -1; + unsigned char *sig = NULL; + +#ifdef USE_OPENSSL_3 + size_t sig_len = 0; + BIGNUM *n = NULL; + const EVP_MD *md = NULL; + + if(EVP_PKEY_get_bn_param(rsactx, OSSL_PKEY_PARAM_RSA_N, &n) > 0) { + sig_len = BN_num_bytes(n); + } + + if(sig_len > 0) + sig = LIBSSH2_ALLOC(session, sig_len); +#else + unsigned int sig_len = 0; sig_len = RSA_size(rsactx); sig = LIBSSH2_ALLOC(session, sig_len); +#endif if(!sig) { return -1; } +#ifdef USE_OPENSSL_3 + if(hash_len == SHA_DIGEST_LENGTH) + md = EVP_sha1(); + else if(hash_len == SHA256_DIGEST_LENGTH) + md = EVP_sha256(); + else if(hash_len == SHA512_DIGEST_LENGTH) + md = EVP_sha512(); + else { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Unsupported hash digest length"); + } + + if(md) { + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(rsactx, NULL); + if(ctx && + EVP_PKEY_sign_init(ctx) > 0 && + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) > 0 && + EVP_PKEY_CTX_set_signature_md(ctx, md) > 0) { + ret = EVP_PKEY_sign(ctx, sig, &sig_len, hash, hash_len); + } + + if(ctx) { + EVP_PKEY_CTX_free(ctx); + } + } +#else if(hash_len == SHA_DIGEST_LENGTH) ret = RSA_sign(NID_sha1, hash, (unsigned int) hash_len, sig, &sig_len, rsactx); @@ -2152,6 +2582,7 @@ _libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session, "Unsupported hash digest length"); ret = -1; } +#endif if(!ret) { LIBSSH2_FREE(session, sig); @@ -2184,14 +2615,41 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, const unsigned char *hash, size_t hash_len, unsigned char *signature) { - DSA_SIG *sig; + DSA_SIG *sig = NULL; const BIGNUM * r; const BIGNUM * s; int r_len, s_len; +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(dsactx, NULL); + unsigned char *buf = NULL; + size_t sig_len = 0; + int size = 0; + + if(EVP_PKEY_get_int_param(dsactx, OSSL_PKEY_PARAM_MAX_SIZE, &size) > 0) { + sig_len = size; + buf = OPENSSL_malloc(size); + } + + if(buf && ctx && EVP_PKEY_sign_init(ctx) > 0) { + EVP_PKEY_sign(ctx, buf, &sig_len, hash, hash_len); + } + + if(ctx) { + EVP_PKEY_CTX_free(ctx); + } + + if(buf) { + const unsigned char *in = buf; + d2i_DSA_SIG(&sig, &in, (long)sig_len); + OPENSSL_clear_free(buf, size); + } +#else (void)hash_len; sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx); +#endif + if(!sig) { return -1; } @@ -2203,20 +2661,20 @@ _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, s = sig->s; #endif r_len = BN_num_bytes(r); - if(r_len < 1 || r_len > 20) { + if(r_len < 1 || r_len > SHA_DIGEST_LENGTH) { DSA_SIG_free(sig); return -1; } s_len = BN_num_bytes(s); - if(s_len < 1 || s_len > 20) { + if(s_len < 1 || s_len > SHA_DIGEST_LENGTH) { DSA_SIG_free(sig); return -1; } - memset(signature, 0, 40); + memset(signature, 0, SHA_DIGEST_LENGTH * 2); - BN_bn2bin(r, signature + (20 - r_len)); - BN_bn2bin(s, signature + 20 + (20 - s_len)); + BN_bn2bin(r, signature + (SHA_DIGEST_LENGTH - r_len)); + BN_bn2bin(s, signature + SHA_DIGEST_LENGTH + (SHA_DIGEST_LENGTH - s_len)); DSA_SIG_free(sig); @@ -2238,10 +2696,47 @@ _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, const BIGNUM *pr = NULL, *ps = NULL; unsigned char *temp_buffer = NULL; unsigned char *out_buffer = NULL; + ECDSA_SIG *sig = NULL; - ECDSA_SIG *sig = ECDSA_do_sign(hash, (int) hash_len, ec_ctx); +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(ec_ctx, NULL); + const unsigned char *p = NULL; + rc = -1; + + if(!ctx) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "out of memory"); + } + + out_buffer_len = EVP_PKEY_get_size(ec_ctx); + temp_buffer = LIBSSH2_ALLOC(session, out_buffer_len); + if(!temp_buffer) { + goto clean_exit; + } + + rc = EVP_PKEY_sign_init(ctx); + if(rc <= 0) { + rc = -1; + goto clean_exit; + } + + rc = EVP_PKEY_sign(ctx, temp_buffer, &out_buffer_len, hash, hash_len); + if(rc <= 0) { + rc = -1; + goto clean_exit; + } + + rc = 0; + + p = temp_buffer; + sig = d2i_ECDSA_SIG(NULL, &p, (long)out_buffer_len); + OPENSSL_clear_free(temp_buffer, out_buffer_len); +#else + sig = ECDSA_do_sign(hash, (int)hash_len, ec_ctx); if(!sig) return -1; +#endif + #ifdef HAVE_OPAQUE_STRUCTS ECDSA_SIG_get0(sig, &pr, &ps); #else @@ -2283,6 +2778,11 @@ clean_exit: if(sig) ECDSA_SIG_free(sig); +#ifdef USE_OPENSSL_3 + if(ctx) + EVP_PKEY_CTX_free(ctx); +#endif + return rc; } #endif /* LIBSSH2_ECDSA */ @@ -2505,8 +3005,7 @@ _libssh2_md5_init(libssh2_md5_ctx *ctx) * So, just return 0 in FIPS mode */ #if OPENSSL_VERSION_NUMBER >= 0x000907000L && \ - defined(OPENSSL_VERSION_MAJOR) && \ - OPENSSL_VERSION_MAJOR < 3 && \ + !defined(USE_OPENSSL_3) && \ !defined(LIBRESSL_VERSION_NUMBER) if(FIPS_mode()) @@ -2545,17 +3044,25 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, EVP_PKEY *pk) { int rc = 0; - EC_KEY *ec = NULL; unsigned char *p; unsigned char *method_buf = NULL; unsigned char *key; size_t key_len = 0; unsigned char *octal_value = NULL; size_t octal_len; + libssh2_curve_type type; + +#ifdef USE_OPENSSL_3 + _libssh2_debug((session, + LIBSSH2_TRACE_AUTH, + "Computing public key from EC private key envelope")); + + type = _libssh2_ecdsa_get_curve_type(pk); +#else + EC_KEY *ec = NULL; const EC_POINT *public_key; const EC_GROUP *group; - BN_CTX *bn_ctx; - libssh2_curve_type type; + BN_CTX *bn_ctx = NULL; _libssh2_debug((session, LIBSSH2_TRACE_AUTH, @@ -2574,6 +3081,7 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, public_key = EC_KEY_get0_public_key(ec); group = EC_KEY_get0_group(ec); type = _libssh2_ecdsa_get_curve_type(ec); +#endif if(is_sk) *method_len = 34; @@ -2602,6 +3110,12 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, goto clean_exit; } +#ifdef USE_OPENSSL_3 + octal_len = EC_MAX_POINT_LEN; + octal_value = LIBSSH2_ALLOC(session, octal_len); + EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_PUB_KEY, + octal_value, octal_len, &octal_len); +#else /* get length */ octal_len = EC_POINT_point2oct(group, public_key, POINT_CONVERSION_UNCOMPRESSED, @@ -2623,6 +3137,7 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, rc = -1; goto clean_exit; } +#endif /* Key form is: type_len(4) + type(method_len) + domain_len(4) + domain(8) + pub_key_len(4) + pub_key(~65). */ @@ -2656,12 +3171,14 @@ gen_publickey_from_ec_evp(LIBSSH2_SESSION *session, clean_exit: +#ifndef USE_OPENSSL_3 if(ec) EC_KEY_free(ec); if(bn_ctx) { BN_CTX_free(bn_ctx); } +#endif if(octal_value) free(octal_value); @@ -2688,8 +3205,16 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, int rc = 0; size_t curvelen, exponentlen, pointlen; unsigned char *curve, *exponent, *point_buf; - EC_KEY *ec_key = NULL; + libssh2_ecdsa_ctx *ec_key = NULL; + +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *fromdata_ctx = NULL; + OSSL_PARAM params[4]; + const char *n = EC_curve_nid2nist(curve_type); + char *group_name = NULL; +#else BIGNUM *bn_exponent; +#endif _libssh2_debug((session, LIBSSH2_TRACE_AUTH, @@ -2714,6 +3239,43 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, return -1; } +#ifdef USE_OPENSSL_3 + if(!n) + return -1; + + fromdata_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + + if(!fromdata_ctx) + goto fail; + + group_name = OPENSSL_zalloc(strlen(n) + 1); + + if(!group_name) + goto fail; + + memcpy(group_name, n, strlen(n)); + _libssh2_swap_bytes(exponent, (unsigned long)exponentlen); + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + group_name, 0); + + params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, + point_buf, pointlen); + + params[2] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_PRIV_KEY, exponent, + exponentlen); + + params[3] = OSSL_PARAM_construct_end(); + + if(EVP_PKEY_fromdata_init(fromdata_ctx) <= 0) + goto fail; + + rc = EVP_PKEY_fromdata(fromdata_ctx, &ec_key, EVP_PKEY_KEYPAIR, params); + rc = rc != 1; + + if(group_name) + OPENSSL_clear_free(group_name, strlen(n)); +#else rc = _libssh2_ecdsa_curve_name_with_octal_new(&ec_key, point_buf, pointlen, curve_type); @@ -2734,29 +3296,46 @@ gen_publickey_from_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, BN_bin2bn(exponent, (int) exponentlen, bn_exponent); rc = (EC_KEY_set_private_key(ec_key, bn_exponent) != 1); +#endif if(rc == 0 && ec_key && pubkeydata && method) { +#ifdef USE_OPENSSL_3 + EVP_PKEY *pk = ec_key; +#else EVP_PKEY *pk = EVP_PKEY_new(); EVP_PKEY_set1_EC_KEY(pk, ec_key); +#endif rc = gen_publickey_from_ec_evp(session, method, method_len, pubkeydata, pubkeydata_len, 0, pk); +#ifndef USE_OPENSSL_3 if(pk) EVP_PKEY_free(pk); +#endif } +#ifdef USE_OPENSSL_3 + if(fromdata_ctx) + EVP_PKEY_CTX_free(fromdata_ctx); +#endif + if(ec_ctx) *ec_ctx = ec_key; else - EC_KEY_free(ec_key); + _libssh2_ecdsa_free(ec_key); return rc; fail: +#ifdef USE_OPENSSL_3 + if(fromdata_ctx) + EVP_PKEY_CTX_free(fromdata_ctx); +#endif + if(ec_key) - EC_KEY_free(ec_key); + _libssh2_ecdsa_free(ec_key); return rc; } @@ -2777,7 +3356,7 @@ gen_publickey_from_sk_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, int rc = 0; size_t curvelen, pointlen, key_len, app_len; unsigned char *curve, *point_buf, *p, *key, *app; - EC_KEY *ec_key = NULL; + libssh2_ecdsa_ctx *ec_key = NULL; _libssh2_debug((session, LIBSSH2_TRACE_AUTH, @@ -2836,15 +3415,21 @@ gen_publickey_from_sk_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, } if(rc == 0 && ec_key && pubkeydata && method) { +#ifdef USE_OPENSSL_3 + EVP_PKEY *pk = ec_key; +#else EVP_PKEY *pk = EVP_PKEY_new(); EVP_PKEY_set1_EC_KEY(pk, ec_key); +#endif rc = gen_publickey_from_ec_evp(session, method, method_len, pubkeydata, pubkeydata_len, 1, pk); +#ifndef USE_OPENSSL_3 if(pk) EVP_PKEY_free(pk); +#endif } if(rc == 0 && pubkeydata) { @@ -2879,13 +3464,13 @@ gen_publickey_from_sk_ecdsa_openssh_priv_data(LIBSSH2_SESSION *session, if(ec_ctx) *ec_ctx = ec_key; else - EC_KEY_free(ec_key); + _libssh2_ecdsa_free(ec_key); return rc; fail: if(ec_key) - EC_KEY_free(ec_key); + _libssh2_ecdsa_free(ec_key); if(application && *application) { LIBSSH2_FREE(session, (void *)application); @@ -3033,7 +3618,11 @@ _libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx, { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; +#endif _libssh2_init_if_needed(); @@ -3060,7 +3649,11 @@ _libssh2_ecdsa_new_private_sk(libssh2_ecdsa_ctx ** ec_ctx, { int rc; +#if defined(USE_OPENSSL_3) + pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_PrivateKey; +#else pem_read_bio_func read_ec = (pem_read_bio_func) &PEM_read_bio_ECPrivateKey; +#endif _libssh2_init_if_needed(); @@ -3100,8 +3693,51 @@ _libssh2_ecdsa_create_key(LIBSSH2_SESSION *session, int ret = 1; size_t octal_len = 0; unsigned char octal_value[EC_MAX_POINT_LEN]; + _libssh2_ec_key *private_key = NULL; + +#ifdef USE_OPENSSL_3 + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + + if(ctx && + EVP_PKEY_keygen_init(ctx) >0 && + EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve_type) > 0) { + ret = EVP_PKEY_keygen(ctx, &private_key); + } + + if(ret <= 0) { + goto clean_exit; + } + + if(out_private_key) + *out_private_key = private_key; + + ret = EVP_PKEY_get_octet_string_param(private_key, OSSL_PKEY_PARAM_PUB_KEY, + NULL, 0, &octal_len); + + if(ret <= 0) { + goto clean_exit; + } + + *out_public_key_octal = LIBSSH2_ALLOC(session, octal_len); + + if(!(*out_public_key_octal)) { + ret = -1; + goto clean_exit; + } + + ret = EVP_PKEY_get_octet_string_param(private_key, OSSL_PKEY_PARAM_PUB_KEY, + octal_value, octal_len, &octal_len); + + if(ret <= 0) { + goto clean_exit; + } + + memcpy(*out_public_key_octal, octal_value, octal_len); + + if(out_public_key_octal_len) + *out_public_key_octal_len = octal_len; +#else const EC_POINT *public_key = NULL; - EC_KEY *private_key = NULL; const EC_GROUP *group = NULL; /* create key */ @@ -3146,11 +3782,16 @@ _libssh2_ecdsa_create_key(LIBSSH2_SESSION *session, if(out_public_key_octal_len) *out_public_key_octal_len = octal_len; +#endif /* USE_OPENSSL_3 */ clean_exit: - +#ifdef USE_OPENSSL_3 + if(ctx) + EVP_PKEY_CTX_free(ctx); +#else if(bn_ctx) BN_CTX_free(bn_ctx); +#endif return (ret == 1) ? 0 : -1; } @@ -3163,16 +3804,120 @@ clean_exit: int _libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key, - const unsigned char *server_public_key, size_t server_public_key_len) + const unsigned char *server_public_key, + size_t server_public_key_len) { int ret = 0; - int rc; + BN_CTX *bn_ctx = NULL; + +#ifdef USE_OPENSSL_3 + char *group_name = NULL; + size_t group_name_len = 0; + unsigned char *out_shared_key = NULL; + EVP_PKEY *peer_key = NULL, *server_key = NULL; + EVP_PKEY_CTX *key_fromdata_ctx = NULL; + EVP_PKEY_CTX *server_key_ctx = NULL; + OSSL_PARAM params[3]; + + size_t out_len = 0; + + if(!k || !(*k) || server_public_key_len <= 0) + return -1; + + bn_ctx = BN_CTX_new(); + if(!bn_ctx) + goto clean_exit; + + key_fromdata_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + if(!key_fromdata_ctx) + goto clean_exit; + + ret = EVP_PKEY_get_utf8_string_param(private_key, + OSSL_PKEY_PARAM_GROUP_NAME, + NULL, 0, &group_name_len); + + if(ret <= 0) + goto clean_exit; + + group_name_len += 1; + group_name = OPENSSL_zalloc(group_name_len); + + if(!group_name) + goto clean_exit; + + ret = EVP_PKEY_get_utf8_string_param(private_key, + OSSL_PKEY_PARAM_GROUP_NAME, + group_name, group_name_len, + &group_name_len); + + if(ret <= 0) + goto clean_exit; + + out_shared_key = OPENSSL_malloc(server_public_key_len); + + if(!out_shared_key) + goto clean_exit; + + memcpy(out_shared_key, server_public_key, server_public_key_len); + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + group_name, 0); + + params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY, + out_shared_key, + server_public_key_len); + + params[2] = OSSL_PARAM_construct_end(); + + ret = EVP_PKEY_fromdata_init(key_fromdata_ctx); + if(ret <= 0) + goto clean_exit; + + ret = EVP_PKEY_fromdata(key_fromdata_ctx, &peer_key, + EVP_PKEY_PUBLIC_KEY, params); + + if(ret <= 0) + goto clean_exit; + + server_key = private_key; + + if(!peer_key || !server_key) { + goto clean_exit; + } + + server_key_ctx = EVP_PKEY_CTX_new(server_key, NULL); + if(!server_key_ctx) { + goto clean_exit; + } + + ret = EVP_PKEY_derive_init(server_key_ctx); + if(ret <= 0) + goto clean_exit; + + ret = EVP_PKEY_derive_set_peer(server_key_ctx, peer_key); + if(ret <= 0) + goto clean_exit; + + ret = EVP_PKEY_derive(server_key_ctx, NULL, &out_len); + if(ret <= 0) + goto clean_exit; + + ret = EVP_PKEY_derive(server_key_ctx, out_shared_key, &out_len); + + if(ret == 1) { + BN_bin2bn(out_shared_key, (int)out_len, *k); + } + else { + ret = -1; + } +#else + int rc = -1; size_t secret_len; unsigned char *secret = NULL; const EC_GROUP *private_key_group; EC_POINT *server_public_key_point; - BN_CTX *bn_ctx = BN_CTX_new(); + bn_ctx = BN_CTX_new(); if(!bn_ctx) return -1; @@ -3209,9 +3954,19 @@ _libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key, } BN_bin2bn(secret, (int) secret_len, *k); +#endif clean_exit: +#ifdef USE_OPENSSL_3 + if(group_name) + OPENSSL_clear_free(group_name, group_name_len); + if(out_shared_key) + OPENSSL_clear_free(out_shared_key, server_public_key_len); + + if(server_key_ctx) + EVP_PKEY_CTX_free(server_key_ctx); +#else if(server_public_key_point) EC_POINT_free(server_public_key_point); @@ -3220,8 +3975,13 @@ clean_exit: if(secret) free(secret); +#endif +#ifdef USE_OPENSSL_3 + return ret == 1 ? 0 : -1; +#else return ret; +#endif } diff --git a/src/openssl.h b/src/openssl.h index a663c6fb..f80a6b43 100644 --- a/src/openssl.h +++ b/src/openssl.h @@ -97,6 +97,11 @@ #include #include +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define USE_OPENSSL_3 1 +#include +#endif + #if (OPENSSL_VERSION_NUMBER >= 0x10100000L && \ !defined(LIBRESSL_VERSION_NUMBER)) || defined(LIBSSH2_WOLFSSL) || \ (defined(LIBRESSL_VERSION_NUMBER) && \ @@ -371,21 +376,42 @@ extern void _libssh2_openssl_crypto_exit(void); #define libssh2_crypto_exit() _libssh2_openssl_crypto_exit() #if LIBSSH2_RSA + +#ifdef USE_OPENSSL_3 +#define libssh2_rsa_ctx EVP_PKEY +#define _libssh2_rsa_free(rsactx) EVP_PKEY_free(rsactx) +#else #define libssh2_rsa_ctx RSA #define _libssh2_rsa_free(rsactx) RSA_free(rsactx) #endif +#endif /* LIBSSH2_RSA */ + #if LIBSSH2_DSA + +#ifdef USE_OPENSSL_3 +#define libssh2_dsa_ctx EVP_PKEY +#define _libssh2_dsa_free(rsactx) EVP_PKEY_free(rsactx) +#else #define libssh2_dsa_ctx DSA #define _libssh2_dsa_free(dsactx) DSA_free(dsactx) #endif +#endif /* LIBSSH2_DSA */ + #if LIBSSH2_ECDSA + +#ifdef USE_OPENSSL_3 +#define libssh2_ecdsa_ctx EVP_PKEY +#define _libssh2_ecdsa_free(ecdsactx) EVP_PKEY_free(ecdsactx) +#define _libssh2_ec_key EVP_PKEY +#else #define libssh2_ecdsa_ctx EC_KEY #define _libssh2_ecdsa_free(ecdsactx) EC_KEY_free(ecdsactx) #define _libssh2_ec_key EC_KEY +#endif typedef enum { LIBSSH2_EC_CURVE_NISTP256 = NID_X9_62_prime256v1,