diff options
Diffstat (limited to 'libs/libssh2/src/wincng.c')
-rw-r--r-- | libs/libssh2/src/wincng.c | 2168 |
1 files changed, 0 insertions, 2168 deletions
diff --git a/libs/libssh2/src/wincng.c b/libs/libssh2/src/wincng.c deleted file mode 100644 index 4bebc6407a..0000000000 --- a/libs/libssh2/src/wincng.c +++ /dev/null @@ -1,2168 +0,0 @@ -/* - * Copyright (C) 2013-2015 Marc Hoersken <info@marc-hoersken.de> - * 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. - */ - -#include "libssh2_priv.h" - -#ifdef LIBSSH2_WINCNG /* compile only if we build with wincng */ - -/* required for cross-compilation against the w64 mingw-runtime package */ -#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) -#undef _WIN32_WINNT -#endif -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#endif - -/* specify the required libraries for dependencies using MSVC */ -#ifdef _MSC_VER -#pragma comment(lib, "bcrypt.lib") -#ifdef HAVE_LIBCRYPT32 -#pragma comment(lib, "crypt32.lib") -#endif -#endif - -#include <windows.h> -#include <bcrypt.h> -#include <math.h> -#include "misc.h" - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif -#ifdef HAVE_LIBCRYPT32 -#include <wincrypt.h> -#endif - -#define PEM_RSA_HEADER "-----BEGIN RSA PRIVATE KEY-----" -#define PEM_RSA_FOOTER "-----END RSA PRIVATE KEY-----" -#define PEM_DSA_HEADER "-----BEGIN DSA PRIVATE KEY-----" -#define PEM_DSA_FOOTER "-----END DSA PRIVATE KEY-----" - - -/*******************************************************************/ -/* - * Windows CNG backend: Missing definitions (for MinGW[-w64]) - */ -#ifndef BCRYPT_SUCCESS -#define BCRYPT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) -#endif - -#ifndef BCRYPT_RNG_ALGORITHM -#define BCRYPT_RNG_ALGORITHM L"RNG" -#endif - -#ifndef BCRYPT_MD5_ALGORITHM -#define BCRYPT_MD5_ALGORITHM L"MD5" -#endif - -#ifndef BCRYPT_SHA1_ALGORITHM -#define BCRYPT_SHA1_ALGORITHM L"SHA1" -#endif - -#ifndef BCRYPT_SHA256_ALGORITHM -#define BCRYPT_SHA256_ALGORITHM L"SHA256" -#endif - -#ifndef BCRYPT_SHA512_ALGORITHM -#define BCRYPT_SHA512_ALGORITHM L"SHA512" -#endif - -#ifndef BCRYPT_RSA_ALGORITHM -#define BCRYPT_RSA_ALGORITHM L"RSA" -#endif - -#ifndef BCRYPT_DSA_ALGORITHM -#define BCRYPT_DSA_ALGORITHM L"DSA" -#endif - -#ifndef BCRYPT_AES_ALGORITHM -#define BCRYPT_AES_ALGORITHM L"AES" -#endif - -#ifndef BCRYPT_RC4_ALGORITHM -#define BCRYPT_RC4_ALGORITHM L"RC4" -#endif - -#ifndef BCRYPT_3DES_ALGORITHM -#define BCRYPT_3DES_ALGORITHM L"3DES" -#endif - -#ifndef BCRYPT_ALG_HANDLE_HMAC_FLAG -#define BCRYPT_ALG_HANDLE_HMAC_FLAG 0x00000008 -#endif - -#ifndef BCRYPT_DSA_PUBLIC_BLOB -#define BCRYPT_DSA_PUBLIC_BLOB L"DSAPUBLICBLOB" -#endif - -#ifndef BCRYPT_DSA_PUBLIC_MAGIC -#define BCRYPT_DSA_PUBLIC_MAGIC 0x42505344 /* DSPB */ -#endif - -#ifndef BCRYPT_DSA_PRIVATE_BLOB -#define BCRYPT_DSA_PRIVATE_BLOB L"DSAPRIVATEBLOB" -#endif - -#ifndef BCRYPT_DSA_PRIVATE_MAGIC -#define BCRYPT_DSA_PRIVATE_MAGIC 0x56505344 /* DSPV */ -#endif - -#ifndef BCRYPT_RSAPUBLIC_BLOB -#define BCRYPT_RSAPUBLIC_BLOB L"RSAPUBLICBLOB" -#endif - -#ifndef BCRYPT_RSAPUBLIC_MAGIC -#define BCRYPT_RSAPUBLIC_MAGIC 0x31415352 /* RSA1 */ -#endif - -#ifndef BCRYPT_RSAFULLPRIVATE_BLOB -#define BCRYPT_RSAFULLPRIVATE_BLOB L"RSAFULLPRIVATEBLOB" -#endif - -#ifndef BCRYPT_RSAFULLPRIVATE_MAGIC -#define BCRYPT_RSAFULLPRIVATE_MAGIC 0x33415352 /* RSA3 */ -#endif - -#ifndef BCRYPT_KEY_DATA_BLOB -#define BCRYPT_KEY_DATA_BLOB L"KeyDataBlob" -#endif - -#ifndef BCRYPT_MESSAGE_BLOCK_LENGTH -#define BCRYPT_MESSAGE_BLOCK_LENGTH L"MessageBlockLength" -#endif - -#ifndef BCRYPT_NO_KEY_VALIDATION -#define BCRYPT_NO_KEY_VALIDATION 0x00000008 -#endif - -#ifndef BCRYPT_BLOCK_PADDING -#define BCRYPT_BLOCK_PADDING 0x00000001 -#endif - -#ifndef BCRYPT_PAD_NONE -#define BCRYPT_PAD_NONE 0x00000001 -#endif - -#ifndef BCRYPT_PAD_PKCS1 -#define BCRYPT_PAD_PKCS1 0x00000002 -#endif - -#ifndef BCRYPT_PAD_OAEP -#define BCRYPT_PAD_OAEP 0x00000004 -#endif - -#ifndef BCRYPT_PAD_PSS -#define BCRYPT_PAD_PSS 0x00000008 -#endif - -#ifndef CRYPT_STRING_ANY -#define CRYPT_STRING_ANY 0x00000007 -#endif - -#ifndef LEGACY_RSAPRIVATE_BLOB -#define LEGACY_RSAPRIVATE_BLOB L"CAPIPRIVATEBLOB" -#endif - -#ifndef PKCS_RSA_PRIVATE_KEY -#define PKCS_RSA_PRIVATE_KEY (LPCSTR)43 -#endif - - -/*******************************************************************/ -/* - * Windows CNG backend: Generic functions - */ - -void -_libssh2_wincng_init(void) -{ - int ret; - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRNG, - BCRYPT_RNG_ALGORITHM, NULL, 0); - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashMD5, - BCRYPT_MD5_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA1, - BCRYPT_SHA1_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA256, - BCRYPT_SHA256_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHashSHA512, - BCRYPT_SHA512_ALGORITHM, NULL, 0); - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacMD5, - BCRYPT_MD5_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA1, - BCRYPT_SHA1_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA256, - BCRYPT_SHA256_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgHmacSHA512, - BCRYPT_SHA512_ALGORITHM, NULL, - BCRYPT_ALG_HANDLE_HMAC_FLAG); - - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRSA, - BCRYPT_RSA_ALGORITHM, NULL, 0); - (void)BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgDSA, - BCRYPT_DSA_ALGORITHM, NULL, 0); - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_CBC, - BCRYPT_AES_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_CBC, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_CBC, - sizeof(BCRYPT_CHAIN_MODE_CBC), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); - } - } - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgAES_ECB, - BCRYPT_AES_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlgAES_ECB, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_ECB, - sizeof(BCRYPT_CHAIN_MODE_ECB), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_ECB, 0); - } - } - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlgRC4_NA, - BCRYPT_RC4_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlgRC4_NA, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_NA, - sizeof(BCRYPT_CHAIN_MODE_NA), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); - } - } - - ret = BCryptOpenAlgorithmProvider(&_libssh2_wincng.hAlg3DES_CBC, - BCRYPT_3DES_ALGORITHM, NULL, 0); - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptSetProperty(_libssh2_wincng.hAlg3DES_CBC, - BCRYPT_CHAINING_MODE, - (PBYTE)BCRYPT_CHAIN_MODE_CBC, - sizeof(BCRYPT_CHAIN_MODE_CBC), 0); - if(!BCRYPT_SUCCESS(ret)) { - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, - 0); - } - } -} - -void -_libssh2_wincng_free(void) -{ - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRNG, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashMD5, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA1, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA256, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHashSHA512, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacMD5, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA1, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA256, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgHmacSHA512, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRSA, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgDSA, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgAES_CBC, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlgRC4_NA, 0); - (void)BCryptCloseAlgorithmProvider(_libssh2_wincng.hAlg3DES_CBC, 0); - - memset(&_libssh2_wincng, 0, sizeof(_libssh2_wincng)); -} - -int -_libssh2_wincng_random(void *buf, int len) -{ - int ret; - - ret = BCryptGenRandom(_libssh2_wincng.hAlgRNG, buf, len, 0); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -static void -_libssh2_wincng_safe_free(void *buf, int len) -{ -#ifndef LIBSSH2_CLEAR_MEMORY - (void)len; -#endif - - if(!buf) - return; - -#ifdef LIBSSH2_CLEAR_MEMORY - if(len > 0) - SecureZeroMemory(buf, len); -#endif - - free(buf); -} - - -/*******************************************************************/ -/* - * Windows CNG backend: Hash functions - */ - -int -_libssh2_wincng_hash_init(_libssh2_wincng_hash_ctx *ctx, - BCRYPT_ALG_HANDLE hAlg, unsigned long hashlen, - unsigned char *key, unsigned long keylen) -{ - BCRYPT_HASH_HANDLE hHash; - unsigned char *pbHashObject; - unsigned long dwHashObject, dwHash, cbData; - int ret; - - ret = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, - (unsigned char *)&dwHash, - sizeof(dwHash), - &cbData, 0); - if((!BCRYPT_SUCCESS(ret)) || dwHash != hashlen) { - return -1; - } - - ret = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, - (unsigned char *)&dwHashObject, - sizeof(dwHashObject), - &cbData, 0); - if(!BCRYPT_SUCCESS(ret)) { - return -1; - } - - pbHashObject = malloc(dwHashObject); - if(!pbHashObject) { - return -1; - } - - - ret = BCryptCreateHash(hAlg, &hHash, - pbHashObject, dwHashObject, - key, keylen, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(pbHashObject, dwHashObject); - return -1; - } - - - ctx->hHash = hHash; - ctx->pbHashObject = pbHashObject; - ctx->dwHashObject = dwHashObject; - ctx->cbHash = dwHash; - - return 0; -} - -int -_libssh2_wincng_hash_update(_libssh2_wincng_hash_ctx *ctx, - const unsigned char *data, unsigned long datalen) -{ - int ret; - - ret = BCryptHashData(ctx->hHash, (unsigned char *)data, datalen, 0); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -int -_libssh2_wincng_hash_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash) -{ - int ret; - - ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0); - - BCryptDestroyHash(ctx->hHash); - ctx->hHash = NULL; - - _libssh2_wincng_safe_free(ctx->pbHashObject, ctx->dwHashObject); - ctx->pbHashObject = NULL; - ctx->dwHashObject = 0; - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -int -_libssh2_wincng_hash(unsigned char *data, unsigned long datalen, - BCRYPT_ALG_HANDLE hAlg, - unsigned char *hash, unsigned long hashlen) -{ - _libssh2_wincng_hash_ctx ctx; - int ret; - - ret = _libssh2_wincng_hash_init(&ctx, hAlg, hashlen, NULL, 0); - if(!ret) { - ret = _libssh2_wincng_hash_update(&ctx, data, datalen); - ret |= _libssh2_wincng_hash_final(&ctx, hash); - } - - return ret; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: HMAC functions - */ - -int -_libssh2_wincng_hmac_final(_libssh2_wincng_hash_ctx *ctx, - unsigned char *hash) -{ - int ret; - - ret = BCryptFinishHash(ctx->hHash, hash, ctx->cbHash, 0); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_hmac_cleanup(_libssh2_wincng_hash_ctx *ctx) -{ - BCryptDestroyHash(ctx->hHash); - ctx->hHash = NULL; - - _libssh2_wincng_safe_free(ctx->pbHashObject, ctx->dwHashObject); - ctx->pbHashObject = NULL; - ctx->dwHashObject = 0; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: Key functions - */ - -int -_libssh2_wincng_key_sha1_verify(_libssh2_wincng_key_ctx *ctx, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len, - unsigned long flags) -{ - BCRYPT_PKCS1_PADDING_INFO paddingInfoPKCS1; - void *pPaddingInfo; - unsigned char *data, *hash; - unsigned long datalen, hashlen; - int ret; - - datalen = m_len; - data = malloc(datalen); - if(!data) { - return -1; - } - - hashlen = SHA_DIGEST_LENGTH; - hash = malloc(hashlen); - if(!hash) { - free(data); - return -1; - } - - memcpy(data, m, datalen); - - ret = _libssh2_wincng_hash(data, datalen, - _libssh2_wincng.hAlgHashSHA1, - hash, hashlen); - - _libssh2_wincng_safe_free(data, datalen); - - if(ret) { - _libssh2_wincng_safe_free(hash, hashlen); - return -1; - } - - datalen = sig_len; - data = malloc(datalen); - if(!data) { - _libssh2_wincng_safe_free(hash, hashlen); - return -1; - } - - if(flags & BCRYPT_PAD_PKCS1) { - paddingInfoPKCS1.pszAlgId = BCRYPT_SHA1_ALGORITHM; - pPaddingInfo = &paddingInfoPKCS1; - } - else - pPaddingInfo = NULL; - - memcpy(data, sig, datalen); - - ret = BCryptVerifySignature(ctx->hKey, pPaddingInfo, - hash, hashlen, data, datalen, flags); - - _libssh2_wincng_safe_free(hash, hashlen); - _libssh2_wincng_safe_free(data, datalen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -#ifdef HAVE_LIBCRYPT32 -static int -_libssh2_wincng_load_pem(LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase, - const char *headerbegin, - const char *headerend, - unsigned char **data, - unsigned int *datalen) -{ - FILE *fp; - int ret; - - fp = fopen(filename, FOPEN_READTEXT); - if(!fp) { - return -1; - } - - ret = _libssh2_pem_parse(session, headerbegin, headerend, - passphrase, - fp, data, datalen); - - fclose(fp); - - return ret; -} - -static int -_libssh2_wincng_load_private(LIBSSH2_SESSION *session, - const char *filename, - const char *passphrase, - unsigned char **ppbEncoded, - unsigned long *pcbEncoded, - int tryLoadRSA, int tryLoadDSA) -{ - unsigned char *data = NULL; - unsigned int datalen = 0; - int ret = -1; - - if(ret && tryLoadRSA) { - ret = _libssh2_wincng_load_pem(session, filename, passphrase, - PEM_RSA_HEADER, PEM_RSA_FOOTER, - &data, &datalen); - } - - if(ret && tryLoadDSA) { - ret = _libssh2_wincng_load_pem(session, filename, passphrase, - PEM_DSA_HEADER, PEM_DSA_FOOTER, - &data, &datalen); - } - - if(!ret) { - *ppbEncoded = data; - *pcbEncoded = datalen; - } - - return ret; -} - -static int -_libssh2_wincng_load_private_memory(LIBSSH2_SESSION *session, - const char *privatekeydata, - size_t privatekeydata_len, - const char *passphrase, - unsigned char **ppbEncoded, - unsigned long *pcbEncoded, - int tryLoadRSA, int tryLoadDSA) -{ - unsigned char *data = NULL; - unsigned int datalen = 0; - int ret = -1; - - (void)passphrase; - - if(ret && tryLoadRSA) { - ret = _libssh2_pem_parse_memory(session, - PEM_RSA_HEADER, PEM_RSA_FOOTER, - privatekeydata, privatekeydata_len, - &data, &datalen); - } - - if(ret && tryLoadDSA) { - ret = _libssh2_pem_parse_memory(session, - PEM_DSA_HEADER, PEM_DSA_FOOTER, - privatekeydata, privatekeydata_len, - &data, &datalen); - } - - if(!ret) { - *ppbEncoded = data; - *pcbEncoded = datalen; - } - - return ret; -} - -static int -_libssh2_wincng_asn_decode(unsigned char *pbEncoded, - unsigned long cbEncoded, - LPCSTR lpszStructType, - unsigned char **ppbDecoded, - unsigned long *pcbDecoded) -{ - unsigned char *pbDecoded = NULL; - unsigned long cbDecoded = 0; - int ret; - - ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - lpszStructType, - pbEncoded, cbEncoded, 0, NULL, - NULL, &cbDecoded); - if(!ret) { - return -1; - } - - pbDecoded = malloc(cbDecoded); - if(!pbDecoded) { - return -1; - } - - ret = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, - lpszStructType, - pbEncoded, cbEncoded, 0, NULL, - pbDecoded, &cbDecoded); - if(!ret) { - _libssh2_wincng_safe_free(pbDecoded, cbDecoded); - return -1; - } - - - *ppbDecoded = pbDecoded; - *pcbDecoded = cbDecoded; - - return 0; -} - -static int -_libssh2_wincng_bn_ltob(unsigned char *pbInput, - unsigned long cbInput, - unsigned char **ppbOutput, - unsigned long *pcbOutput) -{ - unsigned char *pbOutput; - unsigned long cbOutput, index, offset, length; - - if(cbInput < 1) { - return 0; - } - - offset = 0; - length = cbInput - 1; - cbOutput = cbInput; - if(pbInput[length] & (1 << 7)) { - offset++; - cbOutput += offset; - } - - pbOutput = (unsigned char *)malloc(cbOutput); - if(!pbOutput) { - return -1; - } - - pbOutput[0] = 0; - for(index = 0; ((index + offset) < cbOutput) - && (index < cbInput); index++) { - pbOutput[index + offset] = pbInput[length - index]; - } - - - *ppbOutput = pbOutput; - *pcbOutput = cbOutput; - - return 0; -} - -static int -_libssh2_wincng_asn_decode_bn(unsigned char *pbEncoded, - unsigned long cbEncoded, - unsigned char **ppbDecoded, - unsigned long *pcbDecoded) -{ - unsigned char *pbDecoded = NULL, *pbInteger; - unsigned long cbDecoded = 0, cbInteger; - int ret; - - ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, - X509_MULTI_BYTE_UINT, - &pbInteger, &cbInteger); - if(!ret) { - ret = _libssh2_wincng_bn_ltob(((PCRYPT_DATA_BLOB)pbInteger)->pbData, - ((PCRYPT_DATA_BLOB)pbInteger)->cbData, - &pbDecoded, &cbDecoded); - if(!ret) { - *ppbDecoded = pbDecoded; - *pcbDecoded = cbDecoded; - } - _libssh2_wincng_safe_free(pbInteger, cbInteger); - } - - return ret; -} - -static int -_libssh2_wincng_asn_decode_bns(unsigned char *pbEncoded, - unsigned long cbEncoded, - unsigned char ***prpbDecoded, - unsigned long **prcbDecoded, - unsigned long *pcbCount) -{ - PCRYPT_DER_BLOB pBlob; - unsigned char *pbDecoded, **rpbDecoded; - unsigned long cbDecoded, *rcbDecoded, index, length; - int ret; - - ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, - X509_SEQUENCE_OF_ANY, - &pbDecoded, &cbDecoded); - if(!ret) { - length = ((PCRYPT_DATA_BLOB)pbDecoded)->cbData; - - rpbDecoded = malloc(sizeof(PBYTE) * length); - if(rpbDecoded) { - rcbDecoded = malloc(sizeof(DWORD) * length); - if(rcbDecoded) { - for(index = 0; index < length; index++) { - pBlob = &((PCRYPT_DER_BLOB) - ((PCRYPT_DATA_BLOB)pbDecoded)->pbData)[index]; - ret = _libssh2_wincng_asn_decode_bn(pBlob->pbData, - pBlob->cbData, - &rpbDecoded[index], - &rcbDecoded[index]); - if(ret) - break; - } - - if(!ret) { - *prpbDecoded = rpbDecoded; - *prcbDecoded = rcbDecoded; - *pcbCount = length; - } - else { - for(length = 0; length < index; length++) { - _libssh2_wincng_safe_free(rpbDecoded[length], - rcbDecoded[length]); - rpbDecoded[length] = NULL; - rcbDecoded[length] = 0; - } - free(rpbDecoded); - free(rcbDecoded); - } - } - else { - free(rpbDecoded); - ret = -1; - } - } - else { - ret = -1; - } - - _libssh2_wincng_safe_free(pbDecoded, cbDecoded); - } - - return ret; -} -#endif /* HAVE_LIBCRYPT32 */ - -static unsigned long -_libssh2_wincng_bn_size(const unsigned char *bignum, - unsigned long length) -{ - unsigned long offset; - - if(!bignum) - return 0; - - length--; - - offset = 0; - while(!(*(bignum + offset)) && (offset < length)) - offset++; - - length++; - - return length - offset; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: RSA functions - */ - -int -_libssh2_wincng_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) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_RSAKEY_BLOB *rsakey; - LPCWSTR lpszBlobType; - unsigned char *key; - unsigned long keylen, offset, mlen, p1len = 0, p2len = 0; - int ret; - - mlen = max(_libssh2_wincng_bn_size(ndata, nlen), - _libssh2_wincng_bn_size(ddata, dlen)); - offset = sizeof(BCRYPT_RSAKEY_BLOB); - keylen = offset + elen + mlen; - if(ddata && dlen > 0) { - p1len = max(_libssh2_wincng_bn_size(pdata, plen), - _libssh2_wincng_bn_size(e1data, e1len)); - p2len = max(_libssh2_wincng_bn_size(qdata, qlen), - _libssh2_wincng_bn_size(e2data, e2len)); - keylen += p1len * 3 + p2len * 2 + mlen; - } - - key = malloc(keylen); - if(!key) { - return -1; - } - - memset(key, 0, keylen); - - - /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */ - rsakey = (BCRYPT_RSAKEY_BLOB *)key; - rsakey->BitLength = mlen * 8; - rsakey->cbPublicExp = elen; - rsakey->cbModulus = mlen; - - memcpy(key + offset, edata, elen); - offset += elen; - - if(nlen < mlen) - memcpy(key + offset + mlen - nlen, ndata, nlen); - else - memcpy(key + offset, ndata + nlen - mlen, mlen); - - if(ddata && dlen > 0) { - offset += mlen; - - if(plen < p1len) - memcpy(key + offset + p1len - plen, pdata, plen); - else - memcpy(key + offset, pdata + plen - p1len, p1len); - offset += p1len; - - if(qlen < p2len) - memcpy(key + offset + p2len - qlen, qdata, qlen); - else - memcpy(key + offset, qdata + qlen - p2len, p2len); - offset += p2len; - - if(e1len < p1len) - memcpy(key + offset + p1len - e1len, e1data, e1len); - else - memcpy(key + offset, e1data + e1len - p1len, p1len); - offset += p1len; - - if(e2len < p2len) - memcpy(key + offset + p2len - e2len, e2data, e2len); - else - memcpy(key + offset, e2data + e2len - p2len, p2len); - offset += p2len; - - if(coefflen < p1len) - memcpy(key + offset + p1len - coefflen, coeffdata, coefflen); - else - memcpy(key + offset, coeffdata + coefflen - p1len, p1len); - offset += p1len; - - if(dlen < mlen) - memcpy(key + offset + mlen - dlen, ddata, dlen); - else - memcpy(key + offset, ddata + dlen - mlen, mlen); - - lpszBlobType = BCRYPT_RSAFULLPRIVATE_BLOB; - rsakey->Magic = BCRYPT_RSAFULLPRIVATE_MAGIC; - rsakey->cbPrime1 = p1len; - rsakey->cbPrime2 = p2len; - } - else { - lpszBlobType = BCRYPT_RSAPUBLIC_BLOB; - rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC; - rsakey->cbPrime1 = 0; - rsakey->cbPrime2 = 0; - } - - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, lpszBlobType, - &hKey, key, keylen, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - - *rsa = malloc(sizeof(libssh2_rsa_ctx)); - if(!(*rsa)) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - (*rsa)->hKey = hKey; - (*rsa)->pbKeyObject = key; - (*rsa)->cbKeyObject = keylen; - - return 0; -} - -#ifdef HAVE_LIBCRYPT32 -static int -_libssh2_wincng_rsa_new_private_parse(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - unsigned char *pbEncoded, - unsigned long cbEncoded) -{ - BCRYPT_KEY_HANDLE hKey; - unsigned char *pbStructInfo; - unsigned long cbStructInfo; - int ret; - - (void)session; - - ret = _libssh2_wincng_asn_decode(pbEncoded, cbEncoded, - PKCS_RSA_PRIVATE_KEY, - &pbStructInfo, &cbStructInfo); - - _libssh2_wincng_safe_free(pbEncoded, cbEncoded); - - if(ret) { - return -1; - } - - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, - LEGACY_RSAPRIVATE_BLOB, &hKey, - pbStructInfo, cbStructInfo, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(pbStructInfo, cbStructInfo); - return -1; - } - - - *rsa = malloc(sizeof(libssh2_rsa_ctx)); - if(!(*rsa)) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(pbStructInfo, cbStructInfo); - return -1; - } - - (*rsa)->hKey = hKey; - (*rsa)->pbKeyObject = pbStructInfo; - (*rsa)->cbKeyObject = cbStructInfo; - - return 0; -} -#endif /* HAVE_LIBCRYPT32 */ - -int -_libssh2_wincng_rsa_new_private(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - (void)session; - - ret = _libssh2_wincng_load_private(session, filename, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 1, 0); - if(ret) { - return -1; - } - - return _libssh2_wincng_rsa_new_private_parse(rsa, session, - pbEncoded, cbEncoded); -#else - (void)rsa; - (void)filename; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to load RSA key from private key file: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - (void)session; - - ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 1, 0); - if(ret) { - return -1; - } - - return _libssh2_wincng_rsa_new_private_parse(rsa, session, - pbEncoded, cbEncoded); -#else - (void)rsa; - (void)filedata; - (void)filedata_len; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_rsa_sha1_verify(libssh2_rsa_ctx *rsa, - const unsigned char *sig, - unsigned long sig_len, - const unsigned char *m, - unsigned long m_len) -{ - return _libssh2_wincng_key_sha1_verify(rsa, sig, sig_len, m, m_len, - BCRYPT_PAD_PKCS1); -} - -int -_libssh2_wincng_rsa_sha1_sign(LIBSSH2_SESSION *session, - libssh2_rsa_ctx *rsa, - const unsigned char *hash, - size_t hash_len, - unsigned char **signature, - size_t *signature_len) -{ - BCRYPT_PKCS1_PADDING_INFO paddingInfo; - unsigned char *data, *sig; - unsigned long cbData, datalen, siglen; - int ret; - - datalen = (unsigned long)hash_len; - data = malloc(datalen); - if(!data) { - return -1; - } - - paddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM; - - memcpy(data, hash, datalen); - - ret = BCryptSignHash(rsa->hKey, &paddingInfo, - data, datalen, NULL, 0, - &cbData, BCRYPT_PAD_PKCS1); - if(BCRYPT_SUCCESS(ret)) { - siglen = cbData; - sig = LIBSSH2_ALLOC(session, siglen); - if(sig) { - ret = BCryptSignHash(rsa->hKey, &paddingInfo, - data, datalen, sig, siglen, - &cbData, BCRYPT_PAD_PKCS1); - if(BCRYPT_SUCCESS(ret)) { - *signature_len = siglen; - *signature = sig; - } - else { - LIBSSH2_FREE(session, sig); - } - } - else - ret = STATUS_NO_MEMORY; - } - - _libssh2_wincng_safe_free(data, datalen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_rsa_free(libssh2_rsa_ctx *rsa) -{ - if(!rsa) - return; - - BCryptDestroyKey(rsa->hKey); - rsa->hKey = NULL; - - _libssh2_wincng_safe_free(rsa->pbKeyObject, rsa->cbKeyObject); - _libssh2_wincng_safe_free(rsa, sizeof(libssh2_rsa_ctx)); -} - - -/*******************************************************************/ -/* - * Windows CNG backend: DSA functions - */ - -#if LIBSSH2_DSA -int -_libssh2_wincng_dsa_new(libssh2_dsa_ctx **dsa, - const unsigned char *pdata, - unsigned long plen, - const unsigned char *qdata, - unsigned long qlen, - const unsigned char *gdata, - unsigned long glen, - const unsigned char *ydata, - unsigned long ylen, - const unsigned char *xdata, - unsigned long xlen) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_DSA_KEY_BLOB *dsakey; - LPCWSTR lpszBlobType; - unsigned char *key; - unsigned long keylen, offset, length; - int ret; - - length = max(max(_libssh2_wincng_bn_size(pdata, plen), - _libssh2_wincng_bn_size(gdata, glen)), - _libssh2_wincng_bn_size(ydata, ylen)); - offset = sizeof(BCRYPT_DSA_KEY_BLOB); - keylen = offset + length * 3; - if(xdata && xlen > 0) - keylen += 20; - - key = malloc(keylen); - if(!key) { - return -1; - } - - memset(key, 0, keylen); - - - /* https://msdn.microsoft.com/library/windows/desktop/aa833126.aspx */ - dsakey = (BCRYPT_DSA_KEY_BLOB *)key; - dsakey->cbKey = length; - - memset(dsakey->Count, -1, sizeof(dsakey->Count)); - memset(dsakey->Seed, -1, sizeof(dsakey->Seed)); - - if(qlen < 20) - memcpy(dsakey->q + 20 - qlen, qdata, qlen); - else - memcpy(dsakey->q, qdata + qlen - 20, 20); - - if(plen < length) - memcpy(key + offset + length - plen, pdata, plen); - else - memcpy(key + offset, pdata + plen - length, length); - offset += length; - - if(glen < length) - memcpy(key + offset + length - glen, gdata, glen); - else - memcpy(key + offset, gdata + glen - length, length); - offset += length; - - if(ylen < length) - memcpy(key + offset + length - ylen, ydata, ylen); - else - memcpy(key + offset, ydata + ylen - length, length); - - if(xdata && xlen > 0) { - offset += length; - - if(xlen < 20) - memcpy(key + offset + 20 - xlen, xdata, xlen); - else - memcpy(key + offset, xdata + xlen - 20, 20); - - lpszBlobType = BCRYPT_DSA_PRIVATE_BLOB; - dsakey->dwMagic = BCRYPT_DSA_PRIVATE_MAGIC; - } - else { - lpszBlobType = BCRYPT_DSA_PUBLIC_BLOB; - dsakey->dwMagic = BCRYPT_DSA_PUBLIC_MAGIC; - } - - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgDSA, NULL, lpszBlobType, - &hKey, key, keylen, 0); - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - - *dsa = malloc(sizeof(libssh2_dsa_ctx)); - if(!(*dsa)) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(key, keylen); - return -1; - } - - (*dsa)->hKey = hKey; - (*dsa)->pbKeyObject = key; - (*dsa)->cbKeyObject = keylen; - - return 0; -} - -#ifdef HAVE_LIBCRYPT32 -static int -_libssh2_wincng_dsa_new_private_parse(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - unsigned char *pbEncoded, - unsigned long cbEncoded) -{ - unsigned char **rpbDecoded; - unsigned long *rcbDecoded, index, length; - int ret; - - (void)session; - - ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded, - &rpbDecoded, &rcbDecoded, &length); - - _libssh2_wincng_safe_free(pbEncoded, cbEncoded); - - if(ret) { - return -1; - } - - - if(length == 6) { - ret = _libssh2_wincng_dsa_new(dsa, - rpbDecoded[1], rcbDecoded[1], - rpbDecoded[2], rcbDecoded[2], - rpbDecoded[3], rcbDecoded[3], - rpbDecoded[4], rcbDecoded[4], - rpbDecoded[5], rcbDecoded[5]); - } - else { - ret = -1; - } - - for(index = 0; index < length; index++) { - _libssh2_wincng_safe_free(rpbDecoded[index], rcbDecoded[index]); - rpbDecoded[index] = NULL; - rcbDecoded[index] = 0; - } - - free(rpbDecoded); - free(rcbDecoded); - - return ret; -} -#endif /* HAVE_LIBCRYPT32 */ - -int -_libssh2_wincng_dsa_new_private(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filename, - const unsigned char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private(session, filename, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 0, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_dsa_new_private_parse(dsa, session, - pbEncoded, cbEncoded); -#else - (void)dsa; - (void)filename; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to load DSA key from private key file: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_dsa_new_private_frommemory(libssh2_dsa_ctx **dsa, - LIBSSH2_SESSION *session, - const char *filedata, - size_t filedata_len, - unsigned const char *passphrase) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private_memory(session, filedata, filedata_len, - (const char *)passphrase, - &pbEncoded, &cbEncoded, 0, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_dsa_new_private_parse(dsa, session, - pbEncoded, cbEncoded); -#else - (void)dsa; - (void)filedata; - (void)filedata_len; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract private key from memory: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_dsa_sha1_verify(libssh2_dsa_ctx *dsa, - const unsigned char *sig_fixed, - const unsigned char *m, - unsigned long m_len) -{ - return _libssh2_wincng_key_sha1_verify(dsa, sig_fixed, 40, m, m_len, 0); -} - -int -_libssh2_wincng_dsa_sha1_sign(libssh2_dsa_ctx *dsa, - const unsigned char *hash, - unsigned long hash_len, - unsigned char *sig_fixed) -{ - unsigned char *data, *sig; - unsigned long cbData, datalen, siglen; - int ret; - - datalen = hash_len; - data = malloc(datalen); - if(!data) { - return -1; - } - - memcpy(data, hash, datalen); - - ret = BCryptSignHash(dsa->hKey, NULL, data, datalen, - NULL, 0, &cbData, 0); - if(BCRYPT_SUCCESS(ret)) { - siglen = cbData; - if(siglen == 40) { - sig = malloc(siglen); - if(sig) { - ret = BCryptSignHash(dsa->hKey, NULL, data, datalen, - sig, siglen, &cbData, 0); - if(BCRYPT_SUCCESS(ret)) { - memcpy(sig_fixed, sig, siglen); - } - - _libssh2_wincng_safe_free(sig, siglen); - } - else - ret = STATUS_NO_MEMORY; - } - else - ret = STATUS_NO_MEMORY; - } - - _libssh2_wincng_safe_free(data, datalen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_dsa_free(libssh2_dsa_ctx *dsa) -{ - if(!dsa) - return; - - BCryptDestroyKey(dsa->hKey); - dsa->hKey = NULL; - - _libssh2_wincng_safe_free(dsa->pbKeyObject, dsa->cbKeyObject); - _libssh2_wincng_safe_free(dsa, sizeof(libssh2_dsa_ctx)); -} -#endif - - -/*******************************************************************/ -/* - * Windows CNG backend: Key functions - */ - -#ifdef HAVE_LIBCRYPT32 -static unsigned long -_libssh2_wincng_pub_priv_write(unsigned char *key, - unsigned long offset, - const unsigned char *bignum, - const unsigned long length) -{ - _libssh2_htonu32(key + offset, length); - offset += 4; - - memcpy(key + offset, bignum, length); - offset += length; - - return offset; -} - -static int -_libssh2_wincng_pub_priv_keyfile_parse(LIBSSH2_SESSION *session, - unsigned char **method, - size_t *method_len, - unsigned char **pubkeydata, - size_t *pubkeydata_len, - unsigned char *pbEncoded, - unsigned long cbEncoded) -{ - unsigned char **rpbDecoded; - unsigned long *rcbDecoded; - unsigned char *key = NULL, *mth = NULL; - unsigned long keylen = 0, mthlen = 0; - unsigned long index, offset, length; - int ret; - - ret = _libssh2_wincng_asn_decode_bns(pbEncoded, cbEncoded, - &rpbDecoded, &rcbDecoded, &length); - - _libssh2_wincng_safe_free(pbEncoded, cbEncoded); - - if(ret) { - return -1; - } - - - if(length == 9) { /* private RSA key */ - mthlen = 7; - mth = LIBSSH2_ALLOC(session, mthlen); - if(mth) { - memcpy(mth, "ssh-rsa", mthlen); - } - else { - ret = -1; - } - - - keylen = 4 + mthlen + 4 + rcbDecoded[2] + 4 + rcbDecoded[1]; - key = LIBSSH2_ALLOC(session, keylen); - if(key) { - offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[2], - rcbDecoded[2]); - - _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[1], - rcbDecoded[1]); - } - else { - ret = -1; - } - - } - else if(length == 6) { /* private DSA key */ - mthlen = 7; - mth = LIBSSH2_ALLOC(session, mthlen); - if(mth) { - memcpy(mth, "ssh-dss", mthlen); - } - else { - ret = -1; - } - - keylen = 4 + mthlen + 4 + rcbDecoded[1] + 4 + rcbDecoded[2] - + 4 + rcbDecoded[3] + 4 + rcbDecoded[4]; - key = LIBSSH2_ALLOC(session, keylen); - if(key) { - offset = _libssh2_wincng_pub_priv_write(key, 0, mth, mthlen); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[1], - rcbDecoded[1]); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[2], - rcbDecoded[2]); - - offset = _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[3], - rcbDecoded[3]); - - _libssh2_wincng_pub_priv_write(key, offset, - rpbDecoded[4], - rcbDecoded[4]); - } - else { - ret = -1; - } - - } - else { - ret = -1; - } - - - for(index = 0; index < length; index++) { - _libssh2_wincng_safe_free(rpbDecoded[index], rcbDecoded[index]); - rpbDecoded[index] = NULL; - rcbDecoded[index] = 0; - } - - free(rpbDecoded); - free(rcbDecoded); - - - 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; -} -#endif /* HAVE_LIBCRYPT32 */ - -int -_libssh2_wincng_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) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private(session, privatekey, passphrase, - &pbEncoded, &cbEncoded, 1, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_pub_priv_keyfile_parse(session, method, method_len, - pubkeydata, pubkeydata_len, - pbEncoded, cbEncoded); -#else - (void)method; - (void)method_len; - (void)pubkeydata; - (void)pubkeydata_len; - (void)privatekey; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_FILE, - "Unable to load public key from private key file: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -int -_libssh2_wincng_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) -{ -#ifdef HAVE_LIBCRYPT32 - unsigned char *pbEncoded; - unsigned long cbEncoded; - int ret; - - ret = _libssh2_wincng_load_private_memory(session, privatekeydata, - privatekeydata_len, passphrase, - &pbEncoded, &cbEncoded, 1, 1); - if(ret) { - return -1; - } - - return _libssh2_wincng_pub_priv_keyfile_parse(session, method, method_len, - pubkeydata, pubkeydata_len, - pbEncoded, cbEncoded); -#else - (void)method; - (void)method_len; - (void)pubkeydata_len; - (void)pubkeydata; - (void)privatekeydata; - (void)privatekeydata_len; - (void)passphrase; - - return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, - "Unable to extract public key from private key in memory: " - "Method unsupported in Windows CNG backend"); -#endif /* HAVE_LIBCRYPT32 */ -} - -/*******************************************************************/ -/* - * Windows CNG backend: Cipher functions - */ - -int -_libssh2_wincng_cipher_init(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - unsigned char *iv, - unsigned char *secret, - int encrypt) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_KEY_DATA_BLOB_HEADER *header; - unsigned char *pbKeyObject, *pbIV, *key, *pbCtr, *pbIVCopy; - unsigned long dwKeyObject, dwIV, dwCtrLength, dwBlockLength, - cbData, keylen; - int ret; - - (void)encrypt; - - ret = BCryptGetProperty(*type.phAlg, BCRYPT_OBJECT_LENGTH, - (unsigned char *)&dwKeyObject, - sizeof(dwKeyObject), - &cbData, 0); - if(!BCRYPT_SUCCESS(ret)) { - return -1; - } - - ret = BCryptGetProperty(*type.phAlg, BCRYPT_BLOCK_LENGTH, - (unsigned char *)&dwBlockLength, - sizeof(dwBlockLength), - &cbData, 0); - if(!BCRYPT_SUCCESS(ret)) { - return -1; - } - - pbKeyObject = malloc(dwKeyObject); - if(!pbKeyObject) { - return -1; - } - - - keylen = sizeof(BCRYPT_KEY_DATA_BLOB_HEADER) + type.dwKeyLength; - key = malloc(keylen); - if(!key) { - free(pbKeyObject); - return -1; - } - - - header = (BCRYPT_KEY_DATA_BLOB_HEADER *)key; - header->dwMagic = BCRYPT_KEY_DATA_BLOB_MAGIC; - header->dwVersion = BCRYPT_KEY_DATA_BLOB_VERSION1; - header->cbKeyData = type.dwKeyLength; - - memcpy(key + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER), - secret, type.dwKeyLength); - - ret = BCryptImportKey(*type.phAlg, NULL, BCRYPT_KEY_DATA_BLOB, &hKey, - pbKeyObject, dwKeyObject, key, keylen, 0); - - _libssh2_wincng_safe_free(key, keylen); - - if(!BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject); - return -1; - } - - pbIV = NULL; - pbCtr = NULL; - dwIV = 0; - dwCtrLength = 0; - - if(type.useIV || type.ctrMode) { - pbIVCopy = malloc(dwBlockLength); - if(!pbIVCopy) { - BCryptDestroyKey(hKey); - _libssh2_wincng_safe_free(pbKeyObject, dwKeyObject); - return -1; - } - memcpy(pbIVCopy, iv, dwBlockLength); - - if(type.ctrMode) { - pbCtr = pbIVCopy; - dwCtrLength = dwBlockLength; - } - else if(type.useIV) { - pbIV = pbIVCopy; - dwIV = dwBlockLength; - } - } - - ctx->hKey = hKey; - ctx->pbKeyObject = pbKeyObject; - ctx->pbIV = pbIV; - ctx->pbCtr = pbCtr; - ctx->dwKeyObject = dwKeyObject; - ctx->dwIV = dwIV; - ctx->dwBlockLength = dwBlockLength; - ctx->dwCtrLength = dwCtrLength; - - return 0; -} -int -_libssh2_wincng_cipher_crypt(_libssh2_cipher_ctx *ctx, - _libssh2_cipher_type(type), - int encrypt, - unsigned char *block, - size_t blocklen) -{ - unsigned char *pbOutput, *pbInput; - unsigned long cbOutput, cbInput; - int ret; - - (void)type; - - cbInput = (unsigned long)blocklen; - - if(type.ctrMode) { - pbInput = ctx->pbCtr; - } - else { - pbInput = block; - } - - if(encrypt || type.ctrMode) { - ret = BCryptEncrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0); - } - else { - ret = BCryptDecrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, NULL, 0, &cbOutput, 0); - } - if(BCRYPT_SUCCESS(ret)) { - pbOutput = malloc(cbOutput); - if(pbOutput) { - if(encrypt || type.ctrMode) { - ret = BCryptEncrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, - pbOutput, cbOutput, &cbOutput, 0); - } - else { - ret = BCryptDecrypt(ctx->hKey, pbInput, cbInput, NULL, - ctx->pbIV, ctx->dwIV, - pbOutput, cbOutput, &cbOutput, 0); - } - if(BCRYPT_SUCCESS(ret)) { - if(type.ctrMode) { - _libssh2_xor_data(block, block, pbOutput, blocklen); - _libssh2_aes_ctr_increment(ctx->pbCtr, ctx->dwCtrLength); - } - else { - memcpy(block, pbOutput, cbOutput); - } - } - - _libssh2_wincng_safe_free(pbOutput, cbOutput); - } - else - ret = STATUS_NO_MEMORY; - } - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -void -_libssh2_wincng_cipher_dtor(_libssh2_cipher_ctx *ctx) -{ - BCryptDestroyKey(ctx->hKey); - ctx->hKey = NULL; - - _libssh2_wincng_safe_free(ctx->pbKeyObject, ctx->dwKeyObject); - ctx->pbKeyObject = NULL; - ctx->dwKeyObject = 0; - - _libssh2_wincng_safe_free(ctx->pbIV, ctx->dwBlockLength); - ctx->pbIV = NULL; - ctx->dwBlockLength = 0; - - _libssh2_wincng_safe_free(ctx->pbCtr, ctx->dwCtrLength); - ctx->pbCtr = NULL; - ctx->dwCtrLength = 0; -} - - -/*******************************************************************/ -/* - * Windows CNG backend: BigNumber functions - */ - -_libssh2_bn * -_libssh2_wincng_bignum_init(void) -{ - _libssh2_bn *bignum; - - bignum = (_libssh2_bn *)malloc(sizeof(_libssh2_bn)); - if(bignum) { - bignum->bignum = NULL; - bignum->length = 0; - } - - return bignum; -} - -static int -_libssh2_wincng_bignum_resize(_libssh2_bn *bn, unsigned long length) -{ - unsigned char *bignum; - - if(!bn) - return -1; - - if(length == bn->length) - return 0; - -#ifdef LIBSSH2_CLEAR_MEMORY - if(bn->bignum && bn->length > 0 && length < bn->length) { - SecureZeroMemory(bn->bignum + length, bn->length - length); - } -#endif - - bignum = realloc(bn->bignum, length); - if(!bignum) - return -1; - - bn->bignum = bignum; - bn->length = length; - - return 0; -} - -static int -_libssh2_wincng_bignum_rand(_libssh2_bn *rnd, int bits, int top, int bottom) -{ - unsigned char *bignum; - unsigned long length; - - if(!rnd) - return -1; - - length = (unsigned long)(ceil((float)bits / 8) * sizeof(unsigned char)); - if(_libssh2_wincng_bignum_resize(rnd, length)) - return -1; - - bignum = rnd->bignum; - - if(_libssh2_wincng_random(bignum, length)) - return -1; - - /* calculate significant bits in most significant byte */ - bits %= 8; - - /* fill most significant byte with zero padding */ - bignum[0] &= (1 << (8 - bits)) - 1; - - /* set some special last bits in most significant byte */ - if(top == 0) - bignum[0] |= (1 << (7 - bits)); - else if(top == 1) - bignum[0] |= (3 << (6 - bits)); - - /* make odd by setting first bit in least significant byte */ - if(bottom) - bignum[length - 1] |= 1; - - return 0; -} - -static int -_libssh2_wincng_bignum_mod_exp(_libssh2_bn *r, - _libssh2_bn *a, - _libssh2_bn *p, - _libssh2_bn *m) -{ - BCRYPT_KEY_HANDLE hKey; - BCRYPT_RSAKEY_BLOB *rsakey; - unsigned char *key, *bignum; - unsigned long keylen, offset, length; - int ret; - - if(!r || !a || !p || !m) - return -1; - - offset = sizeof(BCRYPT_RSAKEY_BLOB); - keylen = offset + p->length + m->length; - - key = malloc(keylen); - if(!key) - return -1; - - - /* https://msdn.microsoft.com/library/windows/desktop/aa375531.aspx */ - rsakey = (BCRYPT_RSAKEY_BLOB *)key; - rsakey->Magic = BCRYPT_RSAPUBLIC_MAGIC; - rsakey->BitLength = m->length * 8; - rsakey->cbPublicExp = p->length; - rsakey->cbModulus = m->length; - rsakey->cbPrime1 = 0; - rsakey->cbPrime2 = 0; - - memcpy(key + offset, p->bignum, p->length); - offset += p->length; - - memcpy(key + offset, m->bignum, m->length); - - ret = BCryptImportKeyPair(_libssh2_wincng.hAlgRSA, NULL, - BCRYPT_RSAPUBLIC_BLOB, &hKey, key, keylen, - BCRYPT_NO_KEY_VALIDATION); - - if(BCRYPT_SUCCESS(ret)) { - ret = BCryptEncrypt(hKey, a->bignum, a->length, NULL, NULL, 0, - NULL, 0, &length, BCRYPT_PAD_NONE); - if(BCRYPT_SUCCESS(ret)) { - if(!_libssh2_wincng_bignum_resize(r, length)) { - length = max(a->length, length); - bignum = malloc(length); - if(bignum) { - offset = length - a->length; - memset(bignum, 0, offset); - memcpy(bignum + offset, a->bignum, a->length); - - ret = BCryptEncrypt(hKey, bignum, length, NULL, NULL, 0, - r->bignum, r->length, &offset, - BCRYPT_PAD_NONE); - - _libssh2_wincng_safe_free(bignum, length); - - if(BCRYPT_SUCCESS(ret)) { - _libssh2_wincng_bignum_resize(r, offset); - } - } - else - ret = STATUS_NO_MEMORY; - } - else - ret = STATUS_NO_MEMORY; - } - - BCryptDestroyKey(hKey); - } - - _libssh2_wincng_safe_free(key, keylen); - - return BCRYPT_SUCCESS(ret) ? 0 : -1; -} - -int -_libssh2_wincng_bignum_set_word(_libssh2_bn *bn, unsigned long word) -{ - unsigned long offset, number, bits, length; - - if(!bn) - return -1; - - bits = 0; - number = word; - while(number >>= 1) - bits++; - - length = (unsigned long) (ceil(((double)(bits + 1)) / 8.0) * - sizeof(unsigned char)); - if(_libssh2_wincng_bignum_resize(bn, length)) - return -1; - - for(offset = 0; offset < length; offset++) - bn->bignum[offset] = (word >> (offset * 8)) & 0xff; - - return 0; -} - -unsigned long -_libssh2_wincng_bignum_bits(const _libssh2_bn *bn) -{ - unsigned char number; - unsigned long offset, length, bits; - - if(!bn) - return 0; - - length = bn->length - 1; - - offset = 0; - while(!(*(bn->bignum + offset)) && (offset < length)) - offset++; - - bits = (length - offset) * 8; - number = bn->bignum[offset]; - - while(number >>= 1) - bits++; - - bits++; - - return bits; -} - -void -_libssh2_wincng_bignum_from_bin(_libssh2_bn *bn, unsigned long len, - const unsigned char *bin) -{ - unsigned char *bignum; - unsigned long offset, length, bits; - - if(!bn || !bin || !len) - return; - - if(_libssh2_wincng_bignum_resize(bn, len)) - return; - - memcpy(bn->bignum, bin, len); - - bits = _libssh2_wincng_bignum_bits(bn); - length = (unsigned long) (ceil(((double)bits) / 8.0) * - sizeof(unsigned char)); - - offset = bn->length - length; - if(offset > 0) { - memmove(bn->bignum, bn->bignum + offset, length); - -#ifdef LIBSSH2_CLEAR_MEMORY - SecureZeroMemory(bn->bignum + length, offset); -#endif - - bignum = realloc(bn->bignum, length); - if(bignum) { - bn->bignum = bignum; - bn->length = length; - } - } -} - -void -_libssh2_wincng_bignum_to_bin(const _libssh2_bn *bn, unsigned char *bin) -{ - if(bin && bn && bn->bignum && bn->length > 0) { - memcpy(bin, bn->bignum, bn->length); - } -} - -void -_libssh2_wincng_bignum_free(_libssh2_bn *bn) -{ - if(bn) { - if(bn->bignum) { - _libssh2_wincng_safe_free(bn->bignum, bn->length); - bn->bignum = NULL; - } - bn->length = 0; - _libssh2_wincng_safe_free(bn, sizeof(_libssh2_bn)); - } -} - - -/* - * Windows CNG backend: Diffie-Hellman support. - */ - -void -_libssh2_dh_init(_libssh2_dh_ctx *dhctx) -{ - *dhctx = _libssh2_wincng_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 */ - if(_libssh2_wincng_bignum_rand(*dhctx, group_order * 8 - 1, 0, -1)) - return -1; - if(_libssh2_wincng_bignum_mod_exp(public, g, *dhctx, p)) - return -1; - return 0; -} - -int -_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret, - _libssh2_bn *f, _libssh2_bn *p) -{ - /* Compute the shared secret */ - _libssh2_wincng_bignum_mod_exp(secret, f, *dhctx, p); - return 0; -} - -void -_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx) -{ - _libssh2_wincng_bignum_free(*dhctx); - *dhctx = NULL; -} - -#endif /* LIBSSH2_WINCNG */ |