Files
KiTTY/wincrypt/wincrypto.c
T
2019-12-31 17:56:57 +01:00

657 lines
18 KiB
C

#ifdef MOD_WINCRYPT
/*
* PuTTY wincrypt patch main file.
* Author: Ulf Frisk, puttywincrypt@ulffrisk.com
*/
#include "putty.h"
#include "ssh.h"
#include "mpint.h"
#include <windows.h>
#include <wincrypt.h>
#include "bcrypt.h"
#include "ncrypt.h"
#include "wincrypt/wincrypto.h"
/*
* Defines and declarations due to missing declarations in mingw32 and BCC55 headers.
*/
#ifndef CERT_SYSTEM_STORE_CURRENT_USER
#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
#endif /* CERT_SYSTEM_STORE_CURRENT_USER */
#ifndef CERT_STORE_PROV_MEMORY
#define CERT_STORE_PROV_MEMORY ((LPCSTR) 2)
#endif /* CERT_STORE_PROV_MEMORY */
#ifndef CRYPT_FIND_USER_KEYSET_FLAG
#define CRYPT_FIND_USER_KEYSET_FLAG 0x00000001
#endif /* CRYPT_FIND_USER_KEYSET_FLAG */
#ifndef CRYPT_FIND_SILENT_KEYSET_FLAG
#define CRYPT_FIND_SILENT_KEYSET_FLAG 0x00000040
#endif /* CRYPT_FIND_SILENT_KEYSET_FLAG */
#ifndef CERT_CLOSE_STORE_FORCE_FLAG
#define CERT_CLOSE_STORE_FORCE_FLAG 0x00000001
#endif /* CERT_CLOSE_STORE_FORCE_FLAG */
#ifndef CRYPT_ACQUIRE_NO_HEALING
#define CRYPT_ACQUIRE_NO_HEALING 0x00000008
#endif /* CRYPT_ACQUIRE_NO_HEALING */
#ifndef CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG
#define CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG 0x00010000
#endif /* CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG */
#ifndef CERT_NCRYPT_KEY_SPEC
#define CERT_NCRYPT_KEY_SPEC 0xFFFFFFFF
#endif /* CERT_NCRYPT_KEY_SPEC */
typedef ULONG_PTR HCRYPTPROV_OR_NCRYPT_KEY_HANDLE;
#ifndef __BCRYPT_H__
#define BCRYPT_PAD_PKCS1 0x00000002
#define BCRYPT_SHA1_ALGORITHM L"SHA1"
typedef struct _BCRYPT_PKCS1_PADDING_INFO
{
LPCWSTR pszAlgId;
} BCRYPT_PKCS1_PADDING_INFO;
#endif /* __BCRYPT_H__ */
#ifndef CRYPT_ACQUIRE_SILENT_FLAG
#define CRYPT_ACQUIRE_SILENT_FLAG 0x00000040
#endif /* CRYPT_ACQUIRE_SILENT_FLAG */
typedef PCCERT_CONTEXT(WINAPI *DFNCryptUIDlgSelectCertificateFromStore)(HCERTSTORE, HWND, LPCWSTR, LPCWSTR, DWORD, DWORD, PVOID);
/*
* Dynamically lookup NCryptSignHash to avoid link dependency to ncrypt.dll (not supported by Windows XP).
*/
typedef LONG(WINAPI *DFNNCryptSignHash)(ULONG_PTR, PVOID, PBYTE, DWORD, PBYTE, DWORD, PDWORD, DWORD);
/*
* convert sha1 string to binary data
*/
void capi_sha1_to_binary(PSTR szHex, PBYTE pbBin)
{
unsigned char i, h, l;
for (i = 0; i < 20; i++) {
h = szHex[i << 1];
l = szHex[(i << 1) + 1];
pbBin[i] =
(((h >= '0' && h <= '9') ? h - '0' : ((h >= 'a' && h <= 'f') ? h - 'a' + 10 : ((h >= 'A' && h <= 'F') ? h - 'A' + 10 : 0))) << 4) +
(((l >= '0' && l <= '9') ? l - '0' : ((l >= 'a' && l <= 'f') ? l - 'a' + 10 : ((l >= 'A' && l <= 'F') ? l - 'A' + 10 : 0))));
}
}
/*
* Windows XP do not support CryptBinaryToString with raw hex.
*/
PSTR capi_binary_to_hex(PBYTE pbBinary, DWORD cbBinary)
{
PSTR szHex;
DWORD idx;
BYTE b;
szHex = snewn((cbBinary << 1) + 1, char);
szHex[cbBinary << 1] = 0;
for (idx = 0; idx < cbBinary; idx++) {
b = (pbBinary[idx] >> 4) & 0x0F;
szHex[idx << 1] = (b < 10) ? b + '0' : b - 10 + 'a';
b = pbBinary[idx] & 0x0F;
szHex[(idx << 1) + 1] = (b < 10) ? b + '0' : b - 10 + 'a';
}
return szHex;
}
/*
* Reverse a byte array.
*/
void capi_reverse_array(PBYTE pb, DWORD cb)
{
DWORD i;
BYTE t;
for (i = 0; i < cb >> 1; i++) {
t = pb[i];
pb[i] = pb[cb - i - 1];
pb[cb - i - 1] = t;
}
}
/*
* Select a certificate given the criteria provided.
* If a criterion is absent it will be disregarded.
*/
void capi_select_cert_2(PBYTE pbSHA1, LPWSTR wszCN, PCCERT_CONTEXT *ppCertCtx, HCERTSTORE *phStore)
{
HCERTSTORE hStoreMY = NULL, hStoreTMP = NULL;
PCCERT_CONTEXT pCertCtx = NULL;
HMODULE hCryptUIDLL = NULL;
DFNCryptUIDlgSelectCertificateFromStore dfnCryptUIDlgSelectCertificateFromStore;
CRYPT_HASH_BLOB cryptHashBlob;
DWORD dwCertCount = 0;
if (!(hStoreMY = CertOpenStore((LPCSTR)CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, L"MY"))) {
goto error;
}
if (pbSHA1) {
cryptHashBlob.cbData = 20;
cryptHashBlob.pbData = pbSHA1;
if ((*ppCertCtx = CertFindCertificateInStore(hStoreMY, X509_ASN_ENCODING, 0, CERT_FIND_SHA1_HASH, &cryptHashBlob, pCertCtx))) {
*phStore = hStoreMY;
return;
} else {
goto error;
}
}
if (!(hStoreTMP = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL))) {
goto error;
}
while (TRUE) {
if (wszCN) {
pCertCtx = CertFindCertificateInStore(hStoreMY, X509_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR, wszCN, pCertCtx);
} else {
pCertCtx = CertEnumCertificatesInStore(hStoreMY, pCertCtx);
}
if (!pCertCtx) {
break;
}
/*
if (!CryptAcquireCertificatePrivateKey(pCertCtx, CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_NO_HEALING | CRYPT_ACQUIRE_SILENT_FLAG | CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG, NULL, &hCryptProvOrNCryptKey, &dwKeySpec, &fCallerFreeProvAlwaysFalse)) {
continue;
}
*/
dwCertCount++;
CertAddCertificateContextToStore(hStoreTMP, pCertCtx, CERT_STORE_ADD_ALWAYS, NULL);
}
CertCloseStore(hStoreMY, CERT_CLOSE_STORE_FORCE_FLAG);
hStoreMY = NULL;
if (dwCertCount == 1) {
*ppCertCtx = CertEnumCertificatesInStore(hStoreTMP, NULL);
*phStore = hStoreTMP;
return;
} else if ((dwCertCount > 1) &&
(hCryptUIDLL = LoadLibrary("cryptui.dll")) &&
(dfnCryptUIDlgSelectCertificateFromStore = (DFNCryptUIDlgSelectCertificateFromStore)GetProcAddress(hCryptUIDLL, "CryptUIDlgSelectCertificateFromStore")) &&
(*ppCertCtx = dfnCryptUIDlgSelectCertificateFromStore(hStoreTMP, NULL, NULL, NULL, 0, 0, NULL))) {
*phStore = hStoreTMP;
FreeLibrary(hCryptUIDLL);
return;
}
error:
if (hCryptUIDLL) { FreeLibrary(hCryptUIDLL); }
if (hStoreTMP) { CertCloseStore(hStoreTMP, CERT_CLOSE_STORE_FORCE_FLAG); }
if (hStoreMY) { CertCloseStore(hStoreMY, CERT_CLOSE_STORE_FORCE_FLAG); }
*ppCertCtx = NULL;
*phStore = NULL;
}
/*
* Return a malloc'ed string containing the requested subitem.
*/
PSTR capi_select_cert_finditem(PSTR szCert, PCSTR szStart)
{
PSTR ptrStart, ptrEnd, szResult;
ptrStart = strstr(szCert, szStart);
ptrEnd = strstr(szCert, ",");
if (!ptrEnd || ptrEnd < ptrStart) {
ptrEnd = szCert + strlen(szCert);
}
if (!ptrStart || ptrStart > ptrEnd) {
return NULL;
}
ptrStart += strlen(szStart);
szResult = (PSTR)calloc(ptrEnd - ptrStart + 1, sizeof(char));
memcpy(szResult, ptrStart, ptrEnd - ptrStart);
return szResult;
}
/*
* Select a certificate given the definition string.
*/
void capi_select_cert(PSTR szCert, PCCERT_CONTEXT *ppCertCtx, HCERTSTORE *phStore)
{
PSTR szCN = NULL, szThumb, ptrStart, ptrStartAll;
LPWSTR wszCN = NULL;
DWORD i, len;
PBYTE pbThumb = snewn(20, BYTE);
ptrStart = strstr(szCert, "cert://");
ptrStartAll = strstr(szCert, "cert://*");
if (ptrStart != szCert) {
ptrStart = strstr(szCert, "x509://");
ptrStartAll = strstr(szCert, "x509://*");
if (ptrStart != szCert) {
*ppCertCtx = NULL;
*phStore = NULL;
return;
}
}
if (ptrStartAll) {
capi_select_cert_2(NULL, NULL, ppCertCtx, phStore);
return;
}
szThumb = capi_select_cert_finditem(szCert, "thumbprint=");
if (szThumb && 40 == strlen(szThumb)) {
capi_sha1_to_binary(szThumb, pbThumb);
capi_select_cert_2(pbThumb, NULL, ppCertCtx, phStore);
} else {
szCN = capi_select_cert_finditem(szCert, "cn=");
if (szCN) {
len = strlen(szCN);
wszCN = (LPWSTR)calloc(len + 1, sizeof(wchar_t));
for (i = 0; i < len; i++) {
wszCN[i] = szCN[i];
}
}
capi_select_cert_2(NULL, wszCN, ppCertCtx, phStore);
}
if (szCN) { free(szCN); }
if (wszCN) { free(wszCN); }
sfree(pbThumb);
}
/*
* Get rsa key comment on the form "cert://cn=<cn>,thumbprint=<sha1>".
*/
static PSTR capi_get_description(PSTR file, PCCERT_CONTEXT pCertContext)
{
DWORD thumbPrintSize = 20;
BYTE thumbPrint[20];
if (!CryptHashCertificate(0, CALG_SHA1, 0, pCertContext->pbCertEncoded,
pCertContext->cbCertEncoded, (PBYTE)&thumbPrint, &thumbPrintSize)) {
}
PSTR tp = capi_binary_to_hex((PBYTE)&thumbPrint, thumbPrintSize);
return dupcat(file, "thumbprint=", tp, NULL);
}
char *wincrypto_invalid(ssh_key *key, unsigned flags)
{
RSAKey *rsa = container_of(key, RSAKey, sshk);
HCERTSTORE hCertStore;
PCCERT_CONTEXT pCertCtx;
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey = 0;
DWORD dwSpec, cbSig = 0;
BOOL fCallerFreeProvAlwaysFalse = TRUE;
capi_select_cert(rsa->comment, &pCertCtx, &hCertStore);
if (pCertCtx)
{
if (CryptAcquireCertificatePrivateKey(pCertCtx, CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG, 0, &hCryptProvOrNCryptKey, &dwSpec, &fCallerFreeProvAlwaysFalse)) {
return NULL;
}
CertFreeCertificateContext(pCertCtx);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
}
return dupstr("Could not acquire private key..");
}
static void wincrypto_public_blob(ssh_key *key, BinarySink *bs)
{
DWORD cbPublicKeyBlob = 8192;
PBYTE pbPublicKeyBlob = NULL;
bool isX509 = false;
uintmax_t size = 0, i = 0;
RSAKey *rsa = container_of(key, RSAKey, sshk);
if (0 == strncmp("x509://", rsa->comment, 7)) {
isX509 = true;
}
if (isX509) {
size = mp_get_integer(rsa->private_exponent);
for (i = 0; i < size; i++) {
BYTE f = mp_get_byte(rsa->iqmp, (size_t)(size - i - 1));
put_byte(bs, f);
}
} else {
put_stringz(bs, "ssh-rsa");
put_mp_ssh2(bs, rsa->exponent);
put_mp_ssh2(bs, rsa->modulus);
}
}
static ssh_key *wincrypto_new_priv(const ssh_keyalg *self,
ptrlen pub, ptrlen priv)
{
RSAKey *rsa;
BOOL result;
PCCERT_CONTEXT pCertContext;
HCERTSTORE hCertStore;
DWORD cbPublicKeyBlob = 8192;
PBYTE pbPublicKeyBlob = NULL;
RSAPUBKEY *pRSAPubKey;
bool isX509 = false;
int len = strlen(pub.ptr);
if ((len < 7)
|| !(0 == strncmp("cert://", pub.ptr, 7)
|| (isX509 = (0 == strncmp("x509://", pub.ptr, 7))))) {
return NULL;
}
capi_select_cert((PSTR)pub.ptr, &pCertContext, &hCertStore);
if (!pCertContext) {
return NULL;
}
rsa = snew(RSAKey);
rsa->p = mp_from_integer(0);
rsa->q = mp_from_integer(0);
if (isX509)
rsa->sshk.vt = &ssh_x509_wincrypt;
else
rsa->sshk.vt = &ssh_rsa_wincrypt;
rsa->comment = dupstr(pub.ptr);
result = CryptDecodeObject(
X509_ASN_ENCODING,
RSA_CSP_PUBLICKEYBLOB,
pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
0,
(void*)(pbPublicKeyBlob = snewn(cbPublicKeyBlob, BYTE)),
&cbPublicKeyBlob);
if (!result) {
CertFreeCertificateContext(pCertContext);
sfree(pbPublicKeyBlob);
return NULL;
}
pRSAPubKey = (RSAPUBKEY*)(pbPublicKeyBlob + sizeof(BLOBHEADER));
capi_reverse_array(pbPublicKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), pRSAPubKey->bitlen / 8);
rsa->exponent = mp_from_integer(pRSAPubKey->pubexp);
rsa->modulus = mp_from_bytes_be(make_ptrlen(pbPublicKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), pRSAPubKey->bitlen / 8));
rsa->iqmp = mp_from_bytes_be(make_ptrlen(pCertContext->pbCertEncoded, pCertContext->cbCertEncoded));
rsa->private_exponent = mp_from_integer(pCertContext->cbCertEncoded);
// cleanup
sfree(pbPublicKeyBlob);
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
return &rsa->sshk;
}
static void wincrypto_sign(ssh_key *key, ptrlen data,
unsigned flags, BinarySink *bs)
{
HCERTSTORE hCertStore;
PCCERT_CONTEXT pCertCtx;
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey = 0;
HCRYPTHASH hHash = 0;
PBYTE pbSig = NULL;
DWORD dwSpec, cbSig = 0;
BOOL fCallerFreeProvAlwaysFalse = TRUE;
bool isX509 = false;
BCRYPT_PKCS1_PADDING_INFO padInfo;
BCRYPT_ALG_HANDLE hHashAlg = NULL;
BCRYPT_HASH_HANDLE hHashBcrypt = NULL;
NTSTATUS status = 0;
DWORD cbData = 0, cbHash = 0, cbHashObject = 0;
PBYTE pbHashObject = NULL;
PBYTE pbHash = NULL;
unsigned short* bcrypt_alg = NULL;
ALG_ID alg = CALG_SHA1;
const char *sign_alg_name;
RSAKey *rsa = container_of(key, RSAKey, sshk);
int len = strlen(rsa->comment);
if ((len < 7)
|| !(0 == strncmp("cert://", rsa->comment, 7)
|| (isX509 = (0 == strncmp("x509://", rsa->comment, 7))))) {
return;
}
if (isX509) {
alg = CALG_SHA1;
bcrypt_alg = BCRYPT_SHA1_ALGORITHM;
padInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
sign_alg_name = "x509v3-sign-rsa";
} else {
if (flags & SSH_AGENT_RSA_SHA2_256) {
alg = CALG_SHA_256;
bcrypt_alg = BCRYPT_SHA256_ALGORITHM;
padInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM;
sign_alg_name = "rsa-sha2-256";
} else if (flags & SSH_AGENT_RSA_SHA2_512) {
alg = CALG_SHA_512;
bcrypt_alg = BCRYPT_SHA512_ALGORITHM;
padInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM;
sign_alg_name = "rsa-sha2-512";
} else {
alg = CALG_SHA1;
bcrypt_alg = BCRYPT_SHA1_ALGORITHM;
padInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
sign_alg_name = "ssh-rsa";
}
}
capi_select_cert(rsa->comment, &pCertCtx, &hCertStore);
if (pCertCtx)
{
if (CryptAcquireCertificatePrivateKey(pCertCtx, CRYPT_ACQUIRE_CACHE_FLAG | CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG, 0, &hCryptProvOrNCryptKey, &dwSpec, &fCallerFreeProvAlwaysFalse)) {
if (dwSpec == AT_KEYEXCHANGE || dwSpec == AT_SIGNATURE) {
/* A lot faster for smartcards because CryptSignHash for asking buffersize is querying sc already */
cbSig = 2048;
pbSig = snewn(cbSig, BYTE);
/* CSP implementation */
if (!CryptCreateHash((HCRYPTPROV)hCryptProvOrNCryptKey, alg, 0, 0, &hHash)) {
goto Cleanup;
}
if (!CryptHashData(hHash, data.ptr, data.len, 0)) {
goto Cleanup;
}
if (!CryptSignHash(hHash, dwSpec, NULL, 0, pbSig, &cbSig)) {
goto Cleanup;
}
capi_reverse_array(pbSig, cbSig);
put_stringz(bs, sign_alg_name);
put_uint32(bs, cbSig);
put_data(bs, pbSig, cbSig);
} else if (dwSpec == CERT_NCRYPT_KEY_SPEC) {
/* KSP/CNG implementation */
if ((status = BCryptOpenAlgorithmProvider(
&hHashAlg, bcrypt_alg, NULL, 0)) != 0) {
goto Cleanup;
}
if ((status = BCryptGetProperty(
hHashAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0)) != 0) {
goto Cleanup;
}
pbHashObject = snewn(cbHashObject, BYTE);
if (NULL == pbHashObject) {
goto Cleanup;
}
if ((status = BCryptGetProperty(
hHashAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0)) != 0) {
goto Cleanup;
}
pbHash = snewn(cbHash, BYTE);
if (NULL == pbHash) {
goto Cleanup;
}
if ((status = BCryptCreateHash(
hHashAlg, &hHashBcrypt, pbHashObject, cbHashObject, NULL, 0, 0)) != 0) {
goto Cleanup;
}
if ((status = BCryptHashData(
hHashBcrypt, (PUCHAR)data.ptr, data.len, 0)) != 0) {
goto Cleanup;
}
if ((status = BCryptFinishHash(
hHashBcrypt, pbHash, cbHash, 0)) != 0) {
goto Cleanup;
}
if ((status = NCryptSignHash(
hCryptProvOrNCryptKey, &padInfo, pbHash, cbHash, NULL, 0, &cbSig, BCRYPT_PAD_PKCS1)) != 0) {
goto Cleanup;
}
pbSig = snewn(cbSig, BYTE);
if (NULL == pbSig) {
goto Cleanup;
}
if ((status = NCryptSignHash(
hCryptProvOrNCryptKey, &padInfo, pbHash, cbHash, pbSig, cbSig, &cbSig, BCRYPT_PAD_PKCS1)) != 0) {
goto Cleanup;
}
put_stringz(bs, sign_alg_name);
put_uint32(bs, cbSig);
put_data(bs, pbSig, cbSig);
}
}
}
Cleanup:
if (hHashAlg)
BCryptCloseAlgorithmProvider(hHashAlg, 0);
if (hHash)
BCryptDestroyHash(hHashBcrypt);
if (pbHashObject)
sfree(pbHashObject);
if (pbHash)
sfree(pbHash);
if (pbSig)
sfree(pbSig);
if (hHash)
CryptDestroyHash(hHash);
if (pCertCtx)
CertFreeCertificateContext(pCertCtx);
if (hCertStore)
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
}
static void wincrypto_freekey(ssh_key *key)
{
RSAKey *rsa = container_of(key, RSAKey, sshk);
freersakey(rsa);
sfree(rsa);
}
/*
* Load a rsa key from a certificate in windows certificate personal store.
*/
BOOL capi_load_key(const Filename **filename, BinarySink *bs)
{
BOOL result;
PCCERT_CONTEXT pCertContext;
HCERTSTORE hCertStore;
DWORD cbPublicKeyBlob = 8192;
PBYTE pbPublicKeyBlob = NULL;
RSAPUBKEY *pRSAPubKey;
bool isX509 = false;
int len = strlen((*filename)->path);
if ((len < 7)
|| !(0 == strncmp("cert://", (*filename)->path, 7)
|| (isX509 = (0 == strncmp("x509://", (*filename)->path, 7))))) {
return false;
}
capi_select_cert((*filename)->path, &pCertContext, &hCertStore);
if (!pCertContext) {
return false;
}
if ((*filename)->path[7] == '*') {
(*filename)->path[7] = '\0';
(*filename) = filename_from_str(capi_get_description((*filename)->path, pCertContext));
}
result = CryptDecodeObject(
X509_ASN_ENCODING,
RSA_CSP_PUBLICKEYBLOB,
pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData,
0,
(void*)(pbPublicKeyBlob = snewn(cbPublicKeyBlob, BYTE)),
&cbPublicKeyBlob);
if (!result) {
CertFreeCertificateContext(pCertContext);
sfree(pbPublicKeyBlob);
return false;
}
pRSAPubKey = (RSAPUBKEY*)(pbPublicKeyBlob + sizeof(BLOBHEADER));
if (isX509) {
put_data(bs, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
} else {
put_stringz(bs, "ssh-rsa");
put_uint32(bs, 3);
capi_reverse_array((PBYTE)&(pRSAPubKey->pubexp), 4);
put_uint32(bs, pRSAPubKey->pubexp);
capi_reverse_array(pbPublicKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), pRSAPubKey->bitlen / 8);
put_uint16(bs, 1);
put_uint16(bs, pRSAPubKey->bitlen / 8);
put_data(bs, pbPublicKeyBlob + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY), pRSAPubKey->bitlen / 8);
}
/* cleanup */
sfree(pbPublicKeyBlob);
CertFreeCertificateContext(pCertContext);
CertCloseStore(hCertStore, CERT_CLOSE_STORE_FORCE_FLAG);
return true;
}
const ssh_keyalg ssh_rsa_wincrypt = {
NULL /*rsa2_new_pub*/,
wincrypto_new_priv /*rsa2_new_priv*/,
NULL /*rsa2_new_priv_openssh*/,
wincrypto_freekey /*rsa2_freekey*/,
wincrypto_invalid,
wincrypto_sign /*rsa2_sign*/,
NULL /*rsa2_verify*/,
wincrypto_public_blob /*rsa2_public_blob*/,
NULL /*rsa2_private_blob*/,
NULL /*rsa2_openssh_blob*/,
NULL /*rsa2_cache_str*/,
NULL /*rsa2_pubkey_bits*/,
"ssh-rsa",
"rsa2",
NULL,
SSH_AGENT_RSA_SHA2_256 | SSH_AGENT_RSA_SHA2_512,
};
const ssh_keyalg ssh_x509_wincrypt = {
NULL /*rsa2_new_pub*/,
wincrypto_new_priv /*rsa2_new_priv*/,
NULL /*rsa2_new_priv_openssh*/,
wincrypto_freekey /*rsa2_freekey*/,
wincrypto_invalid,
wincrypto_sign /*rsa2_sign*/,
NULL /*rsa2_verify*/,
wincrypto_public_blob /*rsa2_public_blob*/,
NULL /*rsa2_private_blob*/,
NULL /*rsa2_openssh_blob*/,
NULL /*rsa2_cache_str*/,
NULL /*rsa2_pubkey_bits*/,
"x509v3-sign-rsa",
"rsa2",
NULL,
SSH_AGENT_RSA_SHA2_256 | SSH_AGENT_RSA_SHA2_512,
};
#endif