Hello everyone, this feature was originally part of the WinCNG crypto backend, but was dropped in order to get the backend merge-ready on its own.
Now that the WinCNG backend has been merged, I think that the feature is open for discussion and improvement. Attached you will find a slightly modified version of the initial feature that matches the current WinCNG backend. Best regards, Marc
>From abd5177ec1c1bb05c77bc6c6eb1a0d6bb61334f4 Mon Sep 17 00:00:00 2001 From: Marc Hoersken <i...@marc-hoersken.de> Date: Sun, 16 Mar 2014 20:02:17 +0100 Subject: [PATCH] wincng: Added explicit memory overwrite feature to WinCNG backend This re-introduces the original feature proposed during the development of the WinCNG crypto backend. It still needs to be added to libssh2 itself and probably other backends. --- configure.ac | 7 +++ src/wincng.c | 174 +++++++++++++++++++++++++++++++++-------------------------- 2 files changed, 106 insertions(+), 75 deletions(-) diff --git a/configure.ac b/configure.ac index 8e52687..c0a9b91 100644 --- a/configure.ac +++ b/configure.ac @@ -197,6 +197,13 @@ if test "$GEX_NEW" != "no"; then AC_DEFINE(LIBSSH2_DH_GEX_NEW, 1, [Enable newer diffie-hellman-group-exchange-sha1 syntax]) fi +AC_ARG_ENABLE(memory-overwrite, + AC_HELP_STRING([--disable-memory-overwrite],[Disable memory overwrite before being freed]), + [MEMORY_OVERWRITE=$enableval]) +if test "$MEMORY_OVERWRITE" != "no"; then + AC_DEFINE(LIBSSH2_MEMORY_OVERWRITE, 1, [Enable memory overwrite before being freed]) +fi + dnl ************************************************************ dnl option to switch on compiler debug options dnl diff --git a/src/wincng.c b/src/wincng.c index 398fe89..6493f06 100644 --- a/src/wincng.c +++ b/src/wincng.c @@ -255,6 +255,22 @@ _libssh2_wincng_random(void *buf, int len) == STATUS_SUCCESS ? 0 : -1; } +static void +_libssh2_wincng_mfree(void *buf, int len) +{ + if (!buf) + return; + +#ifdef LIBSSH2_MEMORY_OVERWRITE + if (len > 0) + _libssh2_wincng_random(buf, len); +#else + (void)len; +#endif + + free(buf); +} + /*******************************************************************/ /* @@ -297,7 +313,7 @@ _libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx, pbHashObject, dwHashObject, key, keylen, 0); if (ret != STATUS_SUCCESS) { - free(pbHashObject); + _libssh2_wincng_mfree(pbHashObject, dwHashObject); return -1; } @@ -327,11 +343,9 @@ _libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx, ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0); BCryptDestroyHash(ctx->hHash); + ctx->hHash = 0; - if (ctx->pbHashObject) - free(ctx->pbHashObject); - - memset(ctx, 0, sizeof(_libssh2_wincng_hash_ctx)); + _libssh2_wincng_mfree(ctx->pbHashObject, ctx->dwHashObject); return ret; } @@ -372,11 +386,9 @@ void _libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx) { BCryptDestroyHash(ctx->hHash); + ctx->hHash = 0; - if (ctx->pbHashObject) - free(ctx->pbHashObject); - - memset(ctx, 0, sizeof(_libssh2_wincng_hash_ctx)); + _libssh2_wincng_mfree(ctx->pbHashObject, ctx->dwHashObject); } @@ -418,17 +430,17 @@ _libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, _libssh2_wincng.hAlgHashSHA1, hash, hashlen); - free(data); + _libssh2_wincng_mfree(data, datalen); if (ret) { - free(hash); + _libssh2_wincng_mfree(hash, hashlen); return -1; } datalen = sig_len; data = malloc(datalen); if (!data) { - free(hash); + _libssh2_wincng_mfree(hash, hashlen); return -1; } @@ -442,8 +454,8 @@ _libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, ret = BCryptVerifySignature(ctx->hKey, pPaddingInfo, hash, hashlen, data, datalen, flags); - free(hash); - free(data); + _libssh2_wincng_mfree(hash, hashlen); + _libssh2_wincng_mfree(data, datalen); return ret == STATUS_SUCCESS ? 0 : -1; } @@ -535,7 +547,7 @@ _libssh2_wincng_asn_decode(unsigned char *pbEncoded, pbEncoded, cbEncoded, 0, NULL, pbDecoded, &cbDecoded); if (!ret) { - free(pbDecoded); + _libssh2_wincng_mfree(pbDecoded, cbDecoded); return -1; } @@ -605,7 +617,7 @@ _libssh2_wincng_asn_decode_bn(unsigned char *pbEncoded, *ppbDecoded = pbDecoded; *pcbDecoded = cbDecoded; } - free(pbInteger); + _libssh2_wincng_mfree(pbInteger, cbInteger); } return ret; @@ -645,12 +657,9 @@ _libssh2_wincng_asn_decode_bns(unsigned char *pbEncoded, } if (ret) { - for (length = 0; length < index; length++) { - if (rpbDecoded[length]) { - free(rpbDecoded[length]); - rpbDecoded[length] = NULL; - } - } + for (length = 0; length < index; length++) + _libssh2_wincng_mfree(rpbDecoded[length], + rcbDecoded[length]); } else { *prpbDecoded = rpbDecoded; *prcbDecoded = rcbDecoded; @@ -665,7 +674,7 @@ _libssh2_wincng_asn_decode_bns(unsigned char *pbEncoded, ret = -1; } - free(pbDecoded); + _libssh2_wincng_mfree(pbDecoded, cbDecoded); } return ret; @@ -811,7 +820,7 @@ _libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, lpszBlobType, &hKey, key, keylen, 0); if (ret != STATUS_SUCCESS) { - free(key); + _libssh2_wincng_mfree(key, keylen); return -1; } @@ -819,7 +828,7 @@ _libssh2_wincng_rsa_new(libssh2_rsa_ctx **rsa, *rsa = malloc(sizeof(libssh2_rsa_ctx)); if (!(*rsa)) { BCryptDestroyKey(hKey); - free(key); + _libssh2_wincng_mfree(key, keylen); return -1; } @@ -855,7 +864,7 @@ _libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, PKCS_RSA_PRIVATE_KEY, &pbStructInfo, &cbStructInfo); - free(pbEncoded); + _libssh2_wincng_mfree(pbEncoded, cbEncoded); if (ret) { return -1; @@ -866,7 +875,7 @@ _libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, LEGACY_RSAPRIVATE_BLOB, &hKey, pbStructInfo, cbStructInfo, 0); if (ret != STATUS_SUCCESS) { - free(pbStructInfo); + _libssh2_wincng_mfree(pbStructInfo, cbStructInfo); return -1; } @@ -874,7 +883,7 @@ _libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, *rsa = malloc(sizeof(libssh2_rsa_ctx)); if (!(*rsa)) { BCryptDestroyKey(hKey); - free(pbStructInfo); + _libssh2_wincng_mfree(pbStructInfo, cbStructInfo); return -1; } @@ -948,7 +957,7 @@ _libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, ret = STATUS_NO_MEMORY; } - free(data); + _libssh2_wincng_mfree(data, datalen); return ret == STATUS_SUCCESS ? 0 : -1; } @@ -956,16 +965,10 @@ _libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, void _libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa) { - if (!rsa) - return; - BCryptDestroyKey(rsa->hKey); - if (rsa->pbKeyObject) - free(rsa->pbKeyObject); - - memset(rsa, 0, sizeof(libssh2_rsa_ctx)); - free(rsa); + _libssh2_wincng_mfree(rsa->pbKeyObject, rsa->cbKeyObject); + _libssh2_wincng_mfree(rsa, sizeof(libssh2_rsa_ctx)); } @@ -1059,7 +1062,7 @@ _libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, ret = BCryptImportKeyPair(_libssh2_wincng.hAlgDSA, NULL, lpszBlobType, &hKey, key, keylen, 0); if (ret != STATUS_SUCCESS) { - free(key); + _libssh2_wincng_mfree(key, keylen); return -1; } @@ -1067,7 +1070,7 @@ _libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, *dsa = malloc(sizeof(libssh2_dsa_ctx)); if (!(*dsa)) { BCryptDestroyKey(hKey); - free(key); + _libssh2_wincng_mfree(key, keylen); return -1; } @@ -1101,7 +1104,7 @@ _libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa, ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded, &rpbDecoded, &rcbDecoded, &length); - free(pbEncoded); + _libssh2_wincng_mfree(pbEncoded, cbEncoded); if (ret) { return -1; @@ -1119,12 +1122,8 @@ _libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa, ret = -1; } - for (index = 0; index < length; index++) { - if (rpbDecoded[index]) { - free(rpbDecoded[index]); - rpbDecoded[index] = NULL; - } - } + for (index = 0; index < length; index++) + _libssh2_wincng_mfree(rpbDecoded[index], rcbDecoded[index]); free(rpbDecoded); free(rcbDecoded); @@ -1181,14 +1180,14 @@ _libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa, memcpy(sig_fixed, sig, siglen); } - free(sig); + _libssh2_wincng_mfree(sig, siglen); } else ret = STATUS_NO_MEMORY; } else ret = STATUS_NO_MEMORY; } - free(data); + _libssh2_wincng_mfree(data, datalen); return ret == STATUS_SUCCESS ? 0 : -1; } @@ -1196,16 +1195,10 @@ _libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa, void _libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa) { - if (!dsa) - return; - BCryptDestroyKey(dsa->hKey); - if (dsa->pbKeyObject) - free(dsa->pbKeyObject); - - memset(dsa, 0, sizeof(libssh2_dsa_ctx)); - free(dsa); + _libssh2_wincng_mfree(dsa->pbKeyObject, dsa->cbKeyObject); + _libssh2_wincng_mfree(dsa, sizeof(libssh2_dsa_ctx)); } #endif @@ -1255,7 +1248,7 @@ _libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session, ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded, &rpbDecoded, &rcbDecoded, &length); - free(pbEncoded); + _libssh2_wincng_mfree(pbEncoded, cbEncoded); if (ret) { return -1; @@ -1327,12 +1320,8 @@ _libssh2_wincng_pub_priv_keyfile(LIBSSH2_SESSION *session, } - for (index = 0; index < length; index++) { - if (rpbDecoded[index]) { - free(rpbDecoded[index]); - rpbDecoded[index] = NULL; - } - } + for (index = 0; index < length; index++) + _libssh2_wincng_mfree(rpbDecoded[index], rcbDecoded[index]); free(rpbDecoded); free(rcbDecoded); @@ -1427,10 +1416,10 @@ _libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, ret = BCryptImportKey(*type.phAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hKey, pbKeyObject, dwKeyObject, key, keylen, 0); - free(key); + _libssh2_wincng_mfree(key, keylen); if (ret != STATUS_SUCCESS) { - free(pbKeyObject); + _libssh2_wincng_mfree(pbKeyObject, dwKeyObject); return -1; } @@ -1438,7 +1427,7 @@ _libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, pbIV = malloc(dwBlockLength); if (!pbIV) { BCryptDestroyKey(hKey); - free(pbKeyObject); + _libssh2_wincng_mfree(pbKeyObject, dwKeyObject); return -1; } dwIV = dwBlockLength; @@ -1497,7 +1486,7 @@ _libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx, memcpy(block, pbOutput, cbOutput); } - free(pbOutput); + _libssh2_wincng_mfree(pbOutput, cbOutput); } else ret = STATUS_NO_MEMORY; } @@ -1510,12 +1499,11 @@ _libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx) { BCryptDestroyKey(ctx->hKey); - if (ctx->pbKeyObject) { - free(ctx->pbKeyObject); - ctx->pbKeyObject = NULL; - } + _libssh2_wincng_mfree(ctx->pbKeyObject, ctx->dwKeyObject); - memset(ctx, 0, sizeof(_libssh2_cipher_ctx)); +#ifdef LIBSSH2_MEMORY_OVERWRITE + _libssh2_wincng_random(ctx, sizeof(_libssh2_cipher_ctx)); +#endif } @@ -1547,12 +1535,36 @@ _libssh2_wincng_bignum_resize(_libssh2_bn *bn, unsigned long length) if (length == bn->length) return 0; +#ifdef LIBSSH2_MEMORY_OVERWRITE + if (length == 0 && bn->bignum && bn->length > 0) { + _libssh2_wincng_mfree(bn->bignum, bn->length); + + bn->bignum = NULL; + bn->length = 0; + + return 0; + } + + bignum = malloc(length); + if (!bignum) + return -1; + + if (bn->bignum) { + memcpy(bignum, bn->bignum, min(length, bn->length)); + + _libssh2_wincng_mfree(bn->bignum, bn->length); + } + + bn->bignum = bignum; + bn->length = length; +#else bignum = realloc(bn->bignum, length); if (!bignum) return -1; bn->bignum = bignum; bn->length = length; +#endif return 0; } @@ -1654,7 +1666,7 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, r->bignum, r->length, &offset, BCRYPT_PAD_NONE); - free(bignum); + _libssh2_wincng_mfree(bignum, length); if (ret == STATUS_SUCCESS) { _libssh2_wincng_bignum_resize(r, offset); @@ -1668,7 +1680,7 @@ _libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, BCryptDestroyKey(hKey); } - free(key); + _libssh2_wincng_mfree(key, keylen); return ret == STATUS_SUCCESS ? 0 : -1; } @@ -1738,6 +1750,17 @@ _libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len, offset = bn->length - length; if (offset > 0) { +#ifdef LIBSSH2_MEMORY_OVERWRITE + bignum = malloc(length); + if (bignum) { + memcpy(bignum, bn->bignum + offset, length); + + _libssh2_wincng_mfree(bn->bignum, bn->length); + + bn->bignum = bignum; + bn->length = length; + } +#else memmove(bn->bignum, bn->bignum + offset, length); bignum = realloc(bn->bignum, length); @@ -1745,6 +1768,7 @@ _libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len, bn->bignum = bignum; bn->length = length; } +#endif } } } @@ -1763,7 +1787,7 @@ _libssh2_wincng_bignum_free(_libssh2_bn *bn) { if (bn) { if (bn->bignum) { - free(bn->bignum); + _libssh2_wincng_mfree(bn->bignum, bn->length); bn->bignum = NULL; } bn->length = 0; -- 1.8.1.msysgit.1
_______________________________________________ libssh2-devel http://cool.haxx.se/cgi-bin/mailman/listinfo/libssh2-devel