diff options
Diffstat (limited to 'src/mscrypto/certkeys.c')
-rw-r--r-- | src/mscrypto/certkeys.c | 2615 |
1 files changed, 2615 insertions, 0 deletions
diff --git a/src/mscrypto/certkeys.c b/src/mscrypto/certkeys.c new file mode 100644 index 00000000..90daa827 --- /dev/null +++ b/src/mscrypto/certkeys.c @@ -0,0 +1,2615 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <windows.h> +#include <wincrypt.h> + +#ifndef XMLSEC_NO_GOST +#include "csp_oid.h" +#include "csp_calg.h" +#endif + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> +#include <xmlsec/bn.h> + +#include <xmlsec/mscrypto/certkeys.h> +#include <xmlsec/mscrypto/crypto.h> +#include <xmlsec/mscrypto/x509.h> +#include "private.h" + +// GOST CSP don't support keys duplicating, so we use NT4 analogs for these... +#ifndef XMLSEC_NO_GOST +#ifndef XMLSEC_MSCRYPTO_NT4 +#define XMLSEC_MSCRYPTO_NT4 +#endif +#endif + + +/************************************************************************** + * + * Internal MSCrypto PCCERT_CONTEXT key CTX + * + *************************************************************************/ +typedef struct _xmlSecMSCryptoKeyDataCtx xmlSecMSCryptoKeyDataCtx, + *xmlSecMSCryptoKeyDataCtxPtr; + +#ifdef XMLSEC_MSCRYPTO_NT4 +/*- + * A wrapper of HCRYPTKEY, a reference countor is introduced, the function is + * the same as CryptDuplicateKey. Because the CryptDuplicateKey is not support + * by WINNT 4.0, the wrapper will enable the library work on WINNT 4.0 + */ +struct _mscrypt_key { + HCRYPTKEY hKey ; + volatile LONG refcnt ; +} ; + +/*- + * A wrapper of HCRYPTPROV, a reference countor is introduced, the function is + * the same as CryptContextAddRef. Because the CryptContextAddRef is not support + * by WINNT 4.0, the wrapper will enable the library work on WINNT 4.0 + */ +struct _mscrypt_prov { + HCRYPTPROV hProv ; + BOOL fCallerFreeProv ; + volatile LONG refcnt ; +} ; +#endif /* XMLSEC_MSCRYPTO_NT4 */ + +/* + * Since MSCrypto does not provide direct handles to private keys, we support + * only private keys linked to a certificate context. The certificate context + * also provides the public key. Only when no certificate context is used, and + * a public key from xml document is provided, we need HCRYPTKEY.... The focus + * now is however directed to certificates. Wouter + */ +struct _xmlSecMSCryptoKeyDataCtx { +#ifndef XMLSEC_MSCRYPTO_NT4 + HCRYPTPROV hProv; + BOOL fCallerFreeProv; + HCRYPTKEY hKey; +#else /* XMLSEC_MSCRYPTO_NT4 */ + struct _mscrypt_prov* p_prov ; + struct _mscrypt_key* p_key ; +#endif /* XMLSEC_MSCRYPTO_NT4 */ + PCCERT_CONTEXT pCert; + const xmlSecMSCryptoProviderInfo * providers; + DWORD dwKeySpec; + xmlSecKeyDataType type; +}; + +#ifndef XMLSEC_MSCRYPTO_NT4 + +/******************************** Provider *****************************************/ +#define xmlSecMSCryptoKeyDataCtxGetProvider(ctx) (ctx)->hProv + +static void +xmlSecMSCryptoKeyDataCtxCreateProvider(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->hProv = 0; + ctx->fCallerFreeProv = FALSE; +} + +static void +xmlSecMSCryptoKeyDataCtxDestroyProvider(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + if ((ctx->hProv != 0) && (ctx->fCallerFreeProv)) { + CryptReleaseContext(ctx->hProv, 0); + } + ctx->hProv = 0; + ctx->fCallerFreeProv = FALSE; +} + +static void +xmlSecMSCryptoKeyDataCtxSetProvider(xmlSecMSCryptoKeyDataCtxPtr ctx, HCRYPTPROV hProv, BOOL fCallerFreeProv) +{ + xmlSecAssert(ctx != NULL); + + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctx); + ctx->hProv = hProv; + ctx->fCallerFreeProv = fCallerFreeProv; +} + +static int +xmlSecMSCryptoKeyDataCtxDuplicateProvider(xmlSecMSCryptoKeyDataCtxPtr ctxDst, xmlSecMSCryptoKeyDataCtxPtr ctxSrc) { + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxSrc != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctxDst); + + if(ctxSrc->hProv != 0) { + if(!CryptContextAddRef(ctxSrc->hProv, NULL, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptContextAddRef", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctxDst->hProv = ctxSrc->hProv; + ctxDst->fCallerFreeProv = TRUE; + } + return(0); +} + + +/******************************** Key *****************************************/ +#define xmlSecMSCryptoKeyDataCtxGetKey(ctx) ((ctx)->hKey) + +static void +xmlSecMSCryptoKeyDataCtxCreateKey(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->hKey = 0; +} + +static void +xmlSecMSCryptoKeyDataCtxDestroyKey(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + if (ctx->hKey != 0) { + CryptDestroyKey(ctx->hKey); + } + ctx->hKey = 0; +} + +static void +xmlSecMSCryptoKeyDataCtxSetKey(xmlSecMSCryptoKeyDataCtxPtr ctx, HCRYPTKEY hKey) { + xmlSecAssert(ctx != NULL); + + xmlSecMSCryptoKeyDataCtxDestroyKey(ctx); + ctx->hKey = hKey; +} + +static int +xmlSecMSCryptoKeyDataCtxDuplicateKey(xmlSecMSCryptoKeyDataCtxPtr ctxDst, xmlSecMSCryptoKeyDataCtxPtr ctxSrc) { + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxSrc != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyKey(ctxDst); + if (ctxSrc->hKey != 0) { + if (!CryptDuplicateKey(ctxSrc->hKey, NULL, 0, &(ctxDst->hKey))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptDuplicateKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +#else /* XMLSEC_MSCRYPTO_NT4 */ + +/******************************** Provider *****************************************/ +#define xmlSecMSCryptoKeyDataCtxGetProvider(ctx) (((ctx)->p_prov) ? ((ctx)->p_prov->hProv) : 0) + +static void +xmlSecMSCryptoKeyDataCtxCreateProvider(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->p_prov = (struct _mscrypt_prov*)xmlMalloc(sizeof(struct _mscrypt_prov)); + if(ctx->p_prov == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE, + "mscrypt_create_prov" , + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE + ); + } + memset(ctx->p_prov, 0, sizeof(struct _mscrypt_prov)); +} + +static void +xmlSecMSCryptoKeyDataCtxDestroyProvider(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + if(ctx->p_prov != NULL) { + if(InterlockedDecrement(&(ctx->p_prov->refcnt)) <= 0) { + if((ctx->p_prov->hProv != 0) && (ctx->p_prov->fCallerFreeProv)) { + CryptReleaseContext(ctx->p_prov->hProv, 0) ; + } + memset(ctx->p_prov, 0, sizeof(struct _mscrypt_prov)); + xmlFree(ctx->p_prov) ; + } + ctx->p_prov = NULL; + } +} + +static void +xmlSecMSCryptoKeyDataCtxSetProvider(xmlSecMSCryptoKeyDataCtxPtr ctx, HCRYPTPROV hProv, BOOL fCallerFreeProv) +{ + xmlSecAssert(ctx != NULL); + + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctx); + + if((ctx->p_prov != NULL) && (ctx->p_prov->refcnt == 1)) { + if((ctx->p_prov->hProv != 0) && (ctx->p_prov->fCallerFreeProv)) { + CryptReleaseContext(ctx->p_prov->hProv, 0) ; + } + memset(ctx->p_prov, 0, sizeof(struct _mscrypt_prov)); + } else { + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctx); + xmlSecMSCryptoKeyDataCtxCreateProvider(ctx); + } + + ctx->p_prov->hProv = hProv; + ctx->p_prov->fCallerFreeProv = fCallerFreeProv; + ctx->p_prov->refcnt = 1; +} + +static int +xmlSecMSCryptoKeyDataCtxDuplicateProvider(xmlSecMSCryptoKeyDataCtxPtr ctxDst, xmlSecMSCryptoKeyDataCtxPtr ctxSrc) { + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxSrc != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctxDst); + + if (ctxSrc->p_prov != NULL) { + ctxDst->p_prov = ctxSrc->p_prov; + InterlockedIncrement(&(ctxDst->p_prov->refcnt)); + } + + return(0); +} + +/******************************** Key *****************************************/ +#define xmlSecMSCryptoKeyDataCtxGetKey(ctx) (((ctx)->p_key) ? ((ctx)->p_key->hKey) : 0) + +static void +xmlSecMSCryptoKeyDataCtxCreateKey(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->p_key = (struct _mscrypt_key*)xmlMalloc(sizeof(struct _mscrypt_key)); + if(ctx->p_key == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE, + "mscrypt_create_key" , + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE + ); + } + memset(ctx->p_key, 0, sizeof(struct _mscrypt_key)); +} + +static void +xmlSecMSCryptoKeyDataCtxDestroyKey(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + if(ctx->p_key != NULL) { + if(InterlockedDecrement(&(ctx->p_key->refcnt)) <= 0) { + if(ctx->p_key->hKey != 0) { + CryptDestroyKey(ctx->p_key->hKey) ; + } + memset(ctx->p_key, 0, sizeof(struct _mscrypt_key)); + xmlFree(ctx->p_key) ; + } + ctx->p_key = NULL; + } +} + +static void +xmlSecMSCryptoKeyDataCtxSetKey(xmlSecMSCryptoKeyDataCtxPtr ctx, HCRYPTKEY hKey) { + xmlSecAssert(ctx != NULL); + + if((ctx->p_key != NULL) && (ctx->p_key->refcnt == 1)) { + if(ctx->p_key->hKey != 0) { + CryptDestroyKey(ctx->p_key->hKey) ; + } + memset(ctx->p_key, 0, sizeof(struct _mscrypt_key)); + } else { + xmlSecMSCryptoKeyDataCtxDestroyKey(ctx); + xmlSecMSCryptoKeyDataCtxCreateKey(ctx); + } + ctx->p_key->hKey = hKey; + ctx->p_key->refcnt = 1; +} + +static int +xmlSecMSCryptoKeyDataCtxDuplicateKey(xmlSecMSCryptoKeyDataCtxPtr ctxDst, xmlSecMSCryptoKeyDataCtxPtr ctxSrc) { + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxSrc != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyKey(ctxDst); + if (ctxSrc->p_key != NULL) { + ctxDst->p_key = ctxSrc->p_key; + InterlockedIncrement(&(ctxDst->p_key->refcnt)); + } + + return(0); +} + +#endif /* XMLSEC_MSCRYPTO_NT4 */ + +/******************************** Cert *****************************************/ +#define xmlSecMSCryptoKeyDataCtxGetCert(ctx) ((ctx)->pCert) + +static void +xmlSecMSCryptoKeyDataCtxCreateCert(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->pCert = NULL; +} + +static void +xmlSecMSCryptoKeyDataCtxDestroyCert(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + if(ctx->pCert != NULL) { + CertFreeCertificateContext(ctx->pCert); + } + ctx->pCert = NULL; +} + +static void +xmlSecMSCryptoKeyDataCtxSetCert(xmlSecMSCryptoKeyDataCtxPtr ctx, PCCERT_CONTEXT pCert) { + xmlSecAssert(ctx != NULL); + + xmlSecMSCryptoKeyDataCtxDestroyCert(ctx); + ctx->pCert = pCert; +} + +static int +xmlSecMSCryptoKeyDataCtxDuplicateCert(xmlSecMSCryptoKeyDataCtxPtr ctxDst, xmlSecMSCryptoKeyDataCtxPtr ctxSrc) { + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxSrc != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyCert(ctxDst); + if(ctxSrc->pCert != NULL) { + ctxDst->pCert = xmlSecMSCryptoCertDup(ctxSrc->pCert); + if(ctxDst->pCert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoPCCDup", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + return(0); +} + +/****************************************************************************** + * + * xmlSecMSCryptoKeyDataCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecMSCryptoKeyDataSize \ + (sizeof(xmlSecKeyData) + sizeof(xmlSecMSCryptoKeyDataCtx)) +#define xmlSecMSCryptoKeyDataGetCtx(data) \ + ((xmlSecMSCryptoKeyDataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData))) + +static int xmlSecMSCryptoKeyDataDuplicate (xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src); +static void xmlSecMSCryptoKeyDataFinalize (xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataGetSize (xmlSecKeyDataPtr data); + +/** + * xmlSecMSCryptoKeyDataAdoptCert: + * @data: the pointer to MSCrypto pccert data. + * @pCert: the pointer to PCCERT key. + * + * Sets the value of key data. + * + * Returns: 0 on success or a negative value otherwise. + */ +static int +xmlSecMSCryptoKeyDataAdoptCert(xmlSecKeyDataPtr data, PCCERT_CONTEXT pCert, xmlSecKeyDataType type) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + HCRYPTKEY hKey = 0; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), -1); + xmlSecAssert2(pCert != NULL, -1); + xmlSecAssert2(pCert->pCertInfo != NULL, -1); + xmlSecAssert2((type & (xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate)) != 0, -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctx); + xmlSecMSCryptoKeyDataCtxDestroyKey(ctx); + xmlSecMSCryptoKeyDataCtxDestroyCert(ctx); + + ctx->type = type; + + /* Now we acquire a context for this key(pair). The context is needed + * for the real crypto stuff in MS Crypto. + */ + if((type & xmlSecKeyDataTypePrivate) != 0){ + HCRYPTPROV hProv = 0; + BOOL fCallerFreeProv = FALSE; + + if (!CryptAcquireCertificatePrivateKey(pCert, + CRYPT_ACQUIRE_SILENT_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG, + NULL, + &hProv, + &(ctx->dwKeySpec), + &fCallerFreeProv)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptAcquireCertificatePrivateKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecMSCryptoKeyDataCtxSetProvider(ctx, hProv, fCallerFreeProv); + } else if((type & xmlSecKeyDataTypePublic) != 0){ + HCRYPTPROV hProv; + + hProv = xmlSecMSCryptoFindProvider(ctx->providers, NULL, CRYPT_VERIFYCONTEXT, FALSE); + if (hProv == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecMSCryptoKeyDataCtxSetProvider(ctx, hProv, TRUE); + ctx->dwKeySpec = 0; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "Unsupported keytype"); + return(-1); + } + + /* CryptImportPublicKeyInfo is only needed when a real key handle + * is needed. The key handle is needed for de/encrypting and for + * verifying of a signature, *not* for signing. We could call + * CryptImportPublicKeyInfo in xmlSecMSCryptoKeyDataGetKey instead + * so no unnessecary calls to CryptImportPublicKeyInfo are being + * made. WK + */ + if(!CryptImportPublicKeyInfo(xmlSecMSCryptoKeyDataCtxGetProvider(ctx), + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + &(pCert->pCertInfo->SubjectPublicKeyInfo), + &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptImportPublicKeyInfo", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + xmlSecMSCryptoKeyDataCtxSetKey(ctx, hKey); + xmlSecMSCryptoKeyDataCtxSetCert(ctx, pCert); + return(0); +} + +static int +xmlSecMSCryptoKeyDataAdoptKey(xmlSecKeyDataPtr data, + HCRYPTPROV hProv, + BOOL fCallerFreeProv, + HCRYPTKEY hKey, + DWORD dwKeySpec, + xmlSecKeyDataType type) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), -1); + xmlSecAssert2(hKey != 0, -1); + xmlSecAssert2(type & (xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate), -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + xmlSecMSCryptoKeyDataCtxSetProvider(ctx, hProv, fCallerFreeProv); + xmlSecMSCryptoKeyDataCtxSetKey(ctx, hKey); + xmlSecMSCryptoKeyDataCtxSetCert(ctx, NULL); + + ctx->dwKeySpec = dwKeySpec; + ctx->type = type; + + return(0); +} + +/** + * xmlSecMSCryptoKeyDataGetKey: + * @data: the key data to retrieve certificate from. + * @type: type of key requested (public/private) + * + * Native MSCrypto key retrieval from xmlsec keydata. The + * returned HKEY must not be destroyed by the caller. + * + * Returns: HKEY on success or NULL otherwise. + */ +HCRYPTKEY +xmlSecMSCryptoKeyDataGetKey(xmlSecKeyDataPtr data, xmlSecKeyDataType type) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(xmlSecMSCryptoKeyDataCtxGetKey(ctx)); +} + +/** + * xmlSecMSCryptoKeyDataGetDecryptKey: + * @data: the key data pointer + * + * Native MSCrypto decrypt key retrieval from xmlsec keydata. The + * returned HKEY must not be destroyed by the caller. + * + * Returns: HKEY on success or NULL otherwise. + */ +HCRYPTKEY +xmlSecMSCryptoKeyDataGetDecryptKey(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + HCRYPTKEY hKey; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + if( !CryptGetUserKey(xmlSecMSCryptoKeyDataCtxGetProvider(ctx), AT_KEYEXCHANGE, &(hKey))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGetUserKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + return (hKey); +} + +/** + * xmlSecMSCryptoKeyDataGetCert: + * @data: the key data to retrieve certificate from. + * + * Native MSCrypto certificate retrieval from xmlsec keydata. The + * returned PCCERT_CONTEXT must not be released by the caller. + * + * Returns: PCCERT_CONTEXT on success or NULL otherwise. + */ +PCCERT_CONTEXT +xmlSecMSCryptoKeyDataGetCert(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(xmlSecMSCryptoKeyDataCtxGetCert(ctx)); +} + +/** + * xmlSecMSCryptoKeyDataGetMSCryptoProvider: + * @data: the key data + * + * Gets crypto provider handle + * + * Returns: the crypto provider handler or 0 if there is an error. + */ +HCRYPTPROV +xmlSecMSCryptoKeyDataGetMSCryptoProvider(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(xmlSecMSCryptoKeyDataCtxGetProvider(ctx)); +} + +/** + * xmlSecMSCryptoKeyDataGetMSCryptoKeySpec: + * @data: the key data + * + * Gets key spec info. + * + * Returns: the key spec info from key data + */ +DWORD +xmlSecMSCryptoKeyDataGetMSCryptoKeySpec(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(ctx->dwKeySpec); +} + +static int +xmlSecMSCryptoKeyDataDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecMSCryptoKeyDataCtxPtr ctxDst; + xmlSecMSCryptoKeyDataCtxPtr ctxSrc; + + xmlSecAssert2(xmlSecKeyDataIsValid(dst), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(dst, xmlSecMSCryptoKeyDataSize), -1); + xmlSecAssert2(xmlSecKeyDataIsValid(src), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(src, xmlSecMSCryptoKeyDataSize), -1); + + ctxDst = xmlSecMSCryptoKeyDataGetCtx(dst); + xmlSecAssert2(ctxDst != NULL, -1); + + ctxSrc = xmlSecMSCryptoKeyDataGetCtx(src); + xmlSecAssert2(ctxSrc != NULL, -1); + + if(xmlSecMSCryptoKeyDataCtxDuplicateProvider(ctxDst, ctxSrc) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecMSCryptoKeyDataCtxDuplicateProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(xmlSecMSCryptoKeyDataCtxDuplicateKey(ctxDst, ctxSrc) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecMSCryptoKeyDataCtxDuplicateKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(xmlSecMSCryptoKeyDataCtxDuplicateCert(ctxDst, ctxSrc) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecMSCryptoKeyDataCtxDuplicateCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctxDst->dwKeySpec = ctxSrc->dwKeySpec; + ctxDst->providers = ctxSrc->providers; + ctxDst->type = ctxSrc->type; + + return(0); +} + +static void +xmlSecMSCryptoKeyDataInitialize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize)); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert(ctx != NULL); + + memset(ctx, 0, sizeof(xmlSecMSCryptoKeyDataCtx)); + + xmlSecMSCryptoKeyDataCtxCreateProvider(ctx); + xmlSecMSCryptoKeyDataCtxCreateKey(ctx); + xmlSecMSCryptoKeyDataCtxCreateCert(ctx); +} + +static void +xmlSecMSCryptoKeyDataFinalize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize)); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert(ctx != NULL); + + xmlSecMSCryptoKeyDataCtxDestroyKey(ctx); + xmlSecMSCryptoKeyDataCtxDestroyCert(ctx); + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctx); + + memset(ctx, 0, sizeof(xmlSecMSCryptoKeyDataCtx)); +} + +static int +xmlSecMSCryptoKeyDataGetSize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + if(xmlSecMSCryptoKeyDataCtxGetCert(ctx) != NULL) { + xmlSecAssert2(xmlSecMSCryptoKeyDataCtxGetCert(ctx)->pCertInfo != NULL, 0); + return (CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + &(xmlSecMSCryptoKeyDataCtxGetCert(ctx)->pCertInfo->SubjectPublicKeyInfo))); + } else if (xmlSecMSCryptoKeyDataCtxGetKey(ctx) != 0) { + DWORD length = 0; + DWORD lenlen = sizeof(DWORD); + + if (!CryptGetKeyParam(xmlSecMSCryptoKeyDataCtxGetKey(ctx), KP_KEYLEN, (BYTE *)&length, &lenlen, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + return(length); + } + + return (0); +} + +static xmlSecKeyDataType +xmlSecMSCryptoKeyDataGetType(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), xmlSecKeyDataTypeUnknown); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, xmlSecKeyDataTypeUnknown); + + /* We could make a call to CryptFindCertificateKeyProvInfo here, to find out if + * we *really* have a private key or not. However if the certificate is not + * linked to a private key, the call takes an ridiculous amount of time. + * the way it is now is better I think. WK. + */ + return(ctx->type); +} + +/** + * xmlSecMSCryptoCertDup: + * @pCert: the pointer to cert. + * + * Duplicates the @pCert. + * + * Returns: pointer to newly created PCCERT_CONTEXT object or + * NULL if an error occurs. + */ +PCCERT_CONTEXT xmlSecMSCryptoCertDup(PCCERT_CONTEXT pCert) { + PCCERT_CONTEXT ret; + + xmlSecAssert2(pCert != NULL, NULL); + + ret = CertDuplicateCertificateContext(pCert); + if(ret == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(ret); +} + + +/** + * xmlSecMSCryptoCertAdopt: + * @pCert: the pointer to cert. + * @type: the expected key type. + * + * Creates key data value from the cert. + * + * Returns: pointer to newly created xmlsec key or NULL if an error occurs. + */ +xmlSecKeyDataPtr +xmlSecMSCryptoCertAdopt(PCCERT_CONTEXT pCert, xmlSecKeyDataType type) { + xmlSecKeyDataPtr data = NULL; + int ret; + + xmlSecAssert2(pCert != NULL, NULL); + xmlSecAssert2(pCert->pCertInfo != NULL, NULL); + xmlSecAssert2(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId != NULL, NULL); + +#ifndef XMLSEC_NO_RSA + if (!strcmp(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_RSA_RSA)) { + data = xmlSecKeyDataCreate(xmlSecMSCryptoKeyDataRsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecMSCryptoDataRsaId"); + return(NULL); + } + } +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_DSA + if (!strcmp(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_X957_DSA /*szOID_DSALG_SIGN*/)) { + data = xmlSecKeyDataCreate(xmlSecMSCryptoKeyDataDsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecMSCryptoKeyDataDsaId"); + return(NULL); + } + } +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_GOST + if (!strcmp(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_MAGPRO_PUBKEY_SIGN_R3410_2001_CP) || + !strcmp(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_MAGPRO_PUBKEY_SIGN_R3410_2001) || + !strcmp(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_MAGPRO_PUBKEY_SIGN_R3410_94_CP)) { + data = xmlSecKeyDataCreate(xmlSecMSCryptoKeyDataGost2001Id); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecMSCryptoKeyDataGost2001Id"); + return(NULL); + } + } +#endif /* XMLSEC_NO_GOST*/ + + if (NULL == data) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_TYPE, + "PCCERT_CONTEXT key type %s not supported", pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId); + return(NULL); + } + + xmlSecAssert2(data != NULL, NULL); + + ret = xmlSecMSCryptoKeyDataAdoptCert(data, pCert, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoPCCDataAdoptPCC", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(NULL); + } + return(data); +} + + +#ifndef XMLSEC_NO_RSA +/************************************************************************** + * + * <dsig:RSAKeyValue> processing + * + * http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue + * The RSAKeyValue Element + * + * RSA key values have two fields: Modulus and Exponent. + * + * <RSAKeyValue> + * <Modulus>xA7SEU+e0yQH5rm9kbCDN9o3aPIo7HbP7tX6WOocLZAtNfyxSZDU16ksL6W + * jubafOqNEpcwR3RdFsT7bCqnXPBe5ELh5u4VEy19MzxkXRgrMvavzyBpVRgBUwUlV + * 5foK5hhmbktQhyNdy/6LpQRhDUDsTvK+g9Ucj47es9AQJ3U= + * </Modulus> + * <Exponent>AQAB</Exponent> + * </RSAKeyValue> + * + * Arbitrary-length integers (e.g. "bignums" such as RSA moduli) are + * represented in XML as octet strings as defined by the ds:CryptoBinary type. + * + * Schema Definition: + * + * <element name="RSAKeyValue" type="ds:RSAKeyValueType"/> + * <complexType name="RSAKeyValueType"> + * <sequence> + * <element name="Modulus" type="ds:CryptoBinary"/> + * <element name="Exponent" type="ds:CryptoBinary"/> + * </sequence> + * </complexType> + * + * DTD Definition: + * + * <!ELEMENT RSAKeyValue (Modulus, Exponent) > + * <!ELEMENT Modulus (#PCDATA) > + * <!ELEMENT Exponent (#PCDATA) > + * + * ============================================================================ + * + * + *************************************************************************/ + +static int xmlSecMSCryptoKeyDataRsaInitialize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataRsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src); +static void xmlSecMSCryptoKeyDataRsaFinalize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataRsaXmlRead(xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataRsaXmlWrite(xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataRsaGenerate(xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecMSCryptoKeyDataRsaGetType(xmlSecKeyDataPtr data); +static xmlSecSize xmlSecMSCryptoKeyDataRsaGetSize(xmlSecKeyDataPtr data); +static void xmlSecMSCryptoKeyDataRsaDebugDump(xmlSecKeyDataPtr data, FILE* output); +static void xmlSecMSCryptoKeyDataRsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output); + +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataRsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecMSCryptoKeyDataSize, + + /* data */ + xmlSecNameRSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefRSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeRSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecMSCryptoKeyDataRsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecMSCryptoKeyDataRsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecMSCryptoKeyDataRsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecMSCryptoKeyDataRsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecMSCryptoKeyDataRsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecMSCryptoKeyDataRsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecMSCryptoKeyDataRsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecMSCryptoKeyDataRsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecMSCryptoKeyDataRsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecMSCryptoKeyDataRsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Rsa[] = { + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV, PROV_RSA_AES}, + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE, PROV_RSA_AES }, + { MS_STRONG_PROV, PROV_RSA_FULL }, + { MS_ENHANCED_PROV, PROV_RSA_FULL }, + { MS_DEF_PROV, PROV_RSA_FULL }, + { NULL, 0 } +}; + +/** + * xmlSecMSCryptoKeyDataRsaGetKlass: + * + * The MSCrypto RSA CertKey data klass. + * + * Returns: pointer to MSCrypto RSA key data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataRsaGetKlass(void) { + return(&xmlSecMSCryptoKeyDataRsaKlass); +} + +static int +xmlSecMSCryptoKeyDataRsaInitialize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId), xmlSecKeyDataTypeUnknown); + + xmlSecMSCryptoKeyDataInitialize(data); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + ctx->providers = xmlSecMSCryptoProviderInfo_Rsa; + return(0); +} + +static int +xmlSecMSCryptoKeyDataRsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecMSCryptoKeyDataRsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecMSCryptoKeyDataRsaId), -1); + + return(xmlSecMSCryptoKeyDataDuplicate(dst, src)); +} + +static void +xmlSecMSCryptoKeyDataRsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId)); + + xmlSecMSCryptoKeyDataFinalize(data); +} + +static int +xmlSecMSCryptoKeyDataRsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecBn modulus, exponent; + xmlSecBuffer blob; + unsigned int blobBufferLen; + PUBLICKEYSTRUC* pubKeyStruc = NULL; + RSAPUBKEY* pubKey = NULL; + xmlSecByte* modulusBlob = NULL; + xmlSecKeyDataPtr data = NULL; + HCRYPTPROV hProv = 0; + HCRYPTKEY hKey = 0; + xmlNodePtr cur; + int res = -1; + int ret; + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataRsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + if(xmlSecKeyGetValue(key) != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA, + "key already has a value"); + return(-1); + } + + /* initialize buffers */ + ret = xmlSecBnInitialize(&modulus, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "modulus"); + return(-1); + } + + ret = xmlSecBnInitialize(&exponent, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "exponent"); + xmlSecBnFinalize(&modulus); + return(-1); + } + + ret = xmlSecBufferInitialize(&blob, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "blob"); + xmlSecBnFinalize(&modulus); + xmlSecBnFinalize(&exponent); + return(-1); + } + + /* read xml */ + cur = xmlSecGetNextElementNode(node->children); + + /* first is Modulus node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRSAModulus, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + goto done; + } + + ret = xmlSecBnGetNodeValue(&modulus, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&modulus) == 0)){ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is Exponent node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRSAExponent, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + goto done; + } + ret = xmlSecBnGetNodeValue(&exponent, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&exponent) == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeRSAPrivateExponent, xmlSecNs))) { + /* next is X node. It is REQUIRED for private key but + * MSCrypto does not support it. We just ignore it */ + cur = xmlSecGetNextElementNode(cur->next); + } + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "no nodes expected"); + goto done; + } + + /* Now try to create the key */ + blobBufferLen = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + xmlSecBnGetSize(&modulus); + ret = xmlSecBufferSetSize(&blob, blobBufferLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", blobBufferLen); + goto done; + } + + /* Set the PUBLICKEYSTRUC */ + pubKeyStruc = (PUBLICKEYSTRUC *)xmlSecBufferGetData(&blob); + pubKeyStruc->bType = PUBLICKEYBLOB; + pubKeyStruc->bVersion = 0x02; + pubKeyStruc->reserved = 0; + pubKeyStruc->aiKeyAlg = CALG_RSA_KEYX | CALG_RSA_SIGN; + + /* Set the public key header */ + pubKey = (RSAPUBKEY*) (xmlSecBufferGetData(&blob) + sizeof(PUBLICKEYSTRUC)); + pubKey->magic = 0x31415352; /* == RSA1 public */ + pubKey->bitlen = xmlSecBnGetSize(&modulus) * 8; /* Number of bits in prime modulus */ + pubKey->pubexp = 0; + if(sizeof(pubKey->pubexp) < xmlSecBnGetSize(&exponent)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "exponent size=%d", + xmlSecBnGetSize(&exponent)); + goto done; + } + xmlSecAssert2(xmlSecBnGetData(&exponent) != NULL, -1); + memcpy(&(pubKey->pubexp), xmlSecBnGetData(&exponent), xmlSecBnGetSize(&exponent)); + + modulusBlob = (xmlSecByte*) (xmlSecBufferGetData(&blob) + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)); + xmlSecAssert2(xmlSecBnGetData(&modulus) != NULL, -1); + memcpy(modulusBlob, xmlSecBnGetData(&modulus), xmlSecBnGetSize(&modulus)); + + /* Now that we have the blob, import */ + hProv = xmlSecMSCryptoFindProvider(xmlSecMSCryptoProviderInfo_Rsa, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(hProv == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + if (!CryptImportKey(hProv, xmlSecBufferGetData(&blob), xmlSecBufferGetSize(&blob), 0, 0, &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptImportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecMSCryptoKeyDataAdoptKey(data, hProv, TRUE, hKey, 0, xmlSecKeyDataTypePublic); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + hProv = 0; + hKey = 0; + + ret = xmlSecKeySetValue(key, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + goto done; + } + data = NULL; + + /* success */ + res = 0; + +done: + if (hProv == 0) { + CryptReleaseContext(hProv, 0); + } + if (hKey != 0) { + CryptDestroyKey(hKey); + } + if (data != 0) { + xmlSecKeyDataDestroy(data); + } + + xmlSecBnFinalize(&modulus); + xmlSecBnFinalize(&exponent); + xmlSecBufferFinalize(&blob); + return(res); +} + +static int +xmlSecMSCryptoKeyDataRsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + xmlSecBuffer buf; + DWORD dwBlobLen; + xmlSecByte* blob; + PUBLICKEYSTRUC* pubKeyStruc; + RSAPUBKEY *pubKey; + xmlSecSize modulusLen, exponentLen; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataRsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecMSCryptoKeyDataRsaId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(xmlSecKeyGetValue(key)); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(xmlSecMSCryptoKeyDataCtxGetKey(ctx) != 0, -1); + + if (!CryptExportKey(xmlSecMSCryptoKeyDataCtxGetKey(ctx), 0, PUBLICKEYBLOB, 0, NULL, &dwBlobLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferInitialize(&buf, dwBlobLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%ld", dwBlobLen); + return(-1); + } + + blob = xmlSecBufferGetData(&buf); + if (!CryptExportKey(xmlSecMSCryptoKeyDataCtxGetKey(ctx), 0, PUBLICKEYBLOB, 0, blob, &dwBlobLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buf); + return(-1); + } + if (dwBlobLen < sizeof(PUBLICKEYSTRUC)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "blobLen=%ld", dwBlobLen); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* check PUBLICKEYSTRUC */ + pubKeyStruc = (PUBLICKEYSTRUC*)blob; + if(pubKeyStruc->bVersion != 0x02) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKeyStruc->bVersion=%d", pubKeyStruc->bVersion); + xmlSecBufferFinalize(&buf); + return(-1); + } + if(pubKeyStruc->bType != PUBLICKEYBLOB) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKeyStruc->bType=%d", (int)pubKeyStruc->bType); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* check RSAPUBKEY */ + pubKey = (RSAPUBKEY *)(blob + sizeof(PUBLICKEYSTRUC)); + if(pubKey->magic != 0x31415352) { /* RSA public key magic */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKey->magic=0x%08lx", pubKey->magic); + xmlSecBufferFinalize(&buf); + return(-1); + } + modulusLen = pubKey->bitlen / 8; + + if (dwBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + modulusLen) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "blobLen=%ld; modulusLen=%d", dwBlobLen, modulusLen); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY); + + /* first is Modulus node */ + cur = xmlSecAddChild(node, xmlSecNodeRSAModulus, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + ret = xmlSecBnBlobSetNodeValue(blob, modulusLen, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* next is Exponent node. */ + cur = xmlSecAddChild(node, xmlSecNodeRSAExponent, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* Remove leading zero's (from least significant end) */ + blob = (xmlSecByte*)(&(pubKey->pubexp)); + exponentLen = sizeof(pubKey->pubexp); + while (exponentLen > 0 && blob[exponentLen - 1] == 0) { + exponentLen--; + } + + ret = xmlSecBnBlobSetNodeValue(blob, exponentLen, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* next is PrivateExponent node: not supported in MSCrypto */ + + xmlSecBufferFinalize(&buf); + return(0); +} + +static int +xmlSecMSCryptoKeyDataRsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, + xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + HCRYPTPROV hProv = 0; + HCRYPTKEY hKey = 0; + DWORD dwKeySpec; + DWORD dwSize; + int res = -1; + int ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId), -1); + xmlSecAssert2(sizeBits > 0, -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + /* get provider */ + hProv = xmlSecMSCryptoFindProvider(ctx->providers, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(hProv == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + dwKeySpec = AT_KEYEXCHANGE | AT_SIGNATURE; + dwSize = ((sizeBits << 16) | CRYPT_EXPORTABLE); + if (!CryptGenKey(hProv, CALG_RSA_SIGN, dwSize, &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CryptGenKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecMSCryptoKeyDataAdoptKey(data, hProv, TRUE, hKey, dwKeySpec, + xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + hProv = 0; + hKey = 0; + + /* success */ + res = 0; + +done: + if (hProv != 0) { + CryptReleaseContext(hProv, 0); + } + + if (hKey != 0) { + CryptDestroyKey(hKey); + } + + return(res); +} + +static xmlSecKeyDataType +xmlSecMSCryptoKeyDataRsaGetType(xmlSecKeyDataPtr data) { + return(xmlSecMSCryptoKeyDataGetType(data)); +} + +static xmlSecSize +xmlSecMSCryptoKeyDataRsaGetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId), 0); + + return (xmlSecMSCryptoKeyDataGetSize(data)); +} + +static void +xmlSecMSCryptoKeyDataRsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== rsa key: size = %d\n", + xmlSecMSCryptoKeyDataRsaGetSize(data)); +} + +static void xmlSecMSCryptoKeyDataRsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<RSAKeyValue size=\"%d\" />\n", + xmlSecMSCryptoKeyDataRsaGetSize(data)); +} + +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_DSA +/************************************************************************** + * + * <dsig:DSAKeyValue> processing + * + * + * The DSAKeyValue Element (http://www.w3.org/TR/xmldsig-core/#sec-DSAKeyValue) + * + * DSA keys and the DSA signature algorithm are specified in [DSS]. + * DSA public key values can have the following fields: + * + * * P - a prime modulus meeting the [DSS] requirements + * * Q - an integer in the range 2**159 < Q < 2**160 which is a prime + * divisor of P-1 + * * G - an integer with certain properties with respect to P and Q + * * Y - G**X mod P (where X is part of the private key and not made + * public) + * * J - (P - 1) / Q + * * seed - a DSA prime generation seed + * * pgenCounter - a DSA prime generation counter + * + * Parameter J is available for inclusion solely for efficiency as it is + * calculatable from P and Q. Parameters seed and pgenCounter are used in the + * DSA prime number generation algorithm specified in [DSS]. As such, they are + * optional but must either both be present or both be absent. This prime + * generation algorithm is designed to provide assurance that a weak prime is + * not being used and it yields a P and Q value. Parameters P, Q, and G can be + * public and common to a group of users. They might be known from application + * context. As such, they are optional but P and Q must either both appear or + * both be absent. If all of P, Q, seed, and pgenCounter are present, + * implementations are not required to check if they are consistent and are + * free to use either P and Q or seed and pgenCounter. All parameters are + * encoded as base64 [MIME] values. + * + * Arbitrary-length integers (e.g. "bignums" such as RSA moduli) are + * represented in XML as octet strings as defined by the ds:CryptoBinary type. + * + * Schema Definition: + * + * <element name="DSAKeyValue" type="ds:DSAKeyValueType"/> + * <complexType name="DSAKeyValueType"> + * <sequence> + * <sequence minOccurs="0"> + * <element name="P" type="ds:CryptoBinary"/> + * <element name="Q" type="ds:CryptoBinary"/> + * </sequence> + * <element name="G" type="ds:CryptoBinary" minOccurs="0"/> + * <element name="Y" type="ds:CryptoBinary"/> + * <element name="J" type="ds:CryptoBinary" minOccurs="0"/> + * <sequence minOccurs="0"> + * <element name="Seed" type="ds:CryptoBinary"/> + * <element name="PgenCounter" type="ds:CryptoBinary"/> + * </sequence> + * </sequence> + * </complexType> + * + * DTD Definition: + * + * <!ELEMENT DSAKeyValue ((P, Q)?, G?, Y, J?, (Seed, PgenCounter)?) > + * <!ELEMENT P (#PCDATA) > + * <!ELEMENT Q (#PCDATA) > + * <!ELEMENT G (#PCDATA) > + * <!ELEMENT Y (#PCDATA) > + * <!ELEMENT J (#PCDATA) > + * <!ELEMENT Seed (#PCDATA) > + * <!ELEMENT PgenCounter (#PCDATA) > + * + * ============================================================================ + * + * To support reading/writing private keys an X element added (before Y). + * todo: The current implementation does not support Seed and PgenCounter! + * by this the P, Q and G are *required*! + * + *************************************************************************/ +static int xmlSecMSCryptoKeyDataDsaInitialize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataDsaDuplicate(xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecMSCryptoKeyDataDsaFinalize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataDsaXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataDsaXmlWrite(xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataDsaGenerate(xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecMSCryptoKeyDataDsaGetType(xmlSecKeyDataPtr data); +static xmlSecSize xmlSecMSCryptoKeyDataDsaGetSize(xmlSecKeyDataPtr data); +static void xmlSecMSCryptoKeyDataDsaDebugDump(xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecMSCryptoKeyDataDsaDebugXmlDump(xmlSecKeyDataPtr data, + FILE* output); + +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataDsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecMSCryptoKeyDataSize, + + /* data */ + xmlSecNameDSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefDSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeDSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecMSCryptoKeyDataDsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecMSCryptoKeyDataDsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecMSCryptoKeyDataDsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecMSCryptoKeyDataDsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecMSCryptoKeyDataDsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecMSCryptoKeyDataDsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecMSCryptoKeyDataDsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecMSCryptoKeyDataDsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecMSCryptoKeyDataDsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecMSCryptoKeyDataDsaDebugXmlDump,/* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Dss[] = { + { MS_DEF_DSS_PROV, PROV_DSS }, + { NULL, 0 } +}; + + +/** + * xmlSecMSCryptoKeyDataDsaGetKlass: + * + * The DSA key data klass. + * + * Returns: pointer to DSA key data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataDsaGetKlass(void) { + return(&xmlSecMSCryptoKeyDataDsaKlass); +} + + +static int +xmlSecMSCryptoKeyDataDsaInitialize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId), xmlSecKeyDataTypeUnknown); + + xmlSecMSCryptoKeyDataInitialize(data); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + ctx->providers = xmlSecMSCryptoProviderInfo_Dss; + return(0); +} + +static int +xmlSecMSCryptoKeyDataDsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecMSCryptoKeyDataDsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecMSCryptoKeyDataDsaId), -1); + + return(xmlSecMSCryptoKeyDataDuplicate(dst, src)); +} + +static void +xmlSecMSCryptoKeyDataDsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId)); + + xmlSecMSCryptoKeyDataFinalize(data); +} + +static int +xmlSecMSCryptoKeyDataDsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data = NULL; + xmlNodePtr cur; + xmlSecBn p, q, g, y; + xmlSecBuffer blob; + unsigned int blobBufferLen; + PUBLICKEYSTRUC *pubKeyStruc = NULL; + DSSPUBKEY *pubKey = NULL; + DSSSEED* seed = NULL; + BYTE *buf = NULL; + HCRYPTPROV hProv = 0; + HCRYPTKEY hKey = 0; + xmlSecSize i; + int res = -1; + int ret; + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataDsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + if(xmlSecKeyGetValue(key) != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA, + "key already has a value"); + return(-1); + } + + /* initialize buffers */ + ret = xmlSecBnInitialize(&p, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "p"); + return(-1); + } + + ret = xmlSecBnInitialize(&q, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "q"); + xmlSecBnFinalize(&p); + return(-1); + } + + ret = xmlSecBnInitialize(&g, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "g"); + xmlSecBnFinalize(&p); + xmlSecBnFinalize(&q); + return(-1); + } + + ret = xmlSecBnInitialize(&y, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "y"); + xmlSecBnFinalize(&p); + xmlSecBnFinalize(&q); + xmlSecBnFinalize(&g); + return(-1); + } + + ret = xmlSecBufferInitialize(&blob, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "blob"); + xmlSecBnFinalize(&p); + xmlSecBnFinalize(&q); + xmlSecBnFinalize(&g); + xmlSecBnFinalize(&y); + return(-1); + } + + /* read xml */ + cur = xmlSecGetNextElementNode(node->children); + + /* first is P node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAP, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + goto done; + } + + ret = xmlSecBnGetNodeValue(&p, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&p) == 0)){ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is Q node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAQ, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + goto done; + } + ret = xmlSecBnGetNodeValue(&q, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&q) == 0)){ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is G node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAG, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + goto done; + } + ret = xmlSecBnGetNodeValue(&g, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&q) == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAX, xmlSecNs))) { + /* next is X node. It is REQUIRED for private key but + * MSCrypto does not support it, we just ignore it */ + + cur = xmlSecGetNextElementNode(cur->next); + } + + /* next is Y node. */ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAY, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + goto done; + } + ret = xmlSecBnGetNodeValue(&y, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&y) == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", xmlSecErrorsSafeString(xmlSecNodeDSAY)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* todo: add support for J */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAJ, xmlSecDSigNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* todo: add support for seed */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSASeed, xmlSecDSigNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* todo: add support for pgencounter */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAPgenCounter, xmlSecDSigNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* we assume that sizeof(q) < 0x14, sizeof(g) <= sizeof(p) and sizeof(y) <= sizeof(p) */ + blobBufferLen = sizeof(PUBLICKEYSTRUC) + sizeof(DSSPUBKEY) + 3 * xmlSecBnGetSize(&p) + 0x14 + sizeof(DSSSEED); + ret = xmlSecBufferSetSize(&blob, blobBufferLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", blobBufferLen); + goto done; + } + + /* Set PUBLICKEYSTRUC */ + pubKeyStruc = (PUBLICKEYSTRUC *)xmlSecBufferGetData(&blob); + pubKeyStruc->bType = PUBLICKEYBLOB; + pubKeyStruc->bVersion = 0x02; + pubKeyStruc->reserved = 0; + pubKeyStruc->aiKeyAlg = CALG_DSS_SIGN; + + /* Set the public key header */ + pubKey = (DSSPUBKEY *) (xmlSecBufferGetData(&blob) + sizeof(PUBLICKEYSTRUC)); + pubKey->magic = 0x31535344; /* == DSS1 pub key */ + pubKey->bitlen = xmlSecBnGetSize(&p) * 8; /* Number of bits in prime modulus */ + + /* copy the key data */ + buf = (BYTE*) (xmlSecBufferGetData(&blob) + sizeof(PUBLICKEYSTRUC) + sizeof(DSSPUBKEY)); + + /* set p */ + xmlSecAssert2(xmlSecBnGetData(&p) != NULL, -1); + memcpy(buf, xmlSecBnGetData(&p), xmlSecBnGetSize(&p)); + buf += xmlSecBnGetSize(&p); + + /* set q */ + if(xmlSecBnGetSize(&q) > 0x14) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "q", + XMLSEC_ERRORS_R_INVALID_SIZE, + "size=%d > 0x14", xmlSecBnGetSize(&q)); + goto done; + } + xmlSecAssert2(xmlSecBnGetData(&q) != NULL, -1); + memcpy(buf, xmlSecBnGetData(&q), xmlSecBnGetSize(&q)); + buf += xmlSecBnGetSize(&q); + + /* Pad with zeros */ + for(i = xmlSecBnGetSize(&q); i < 0x14; ++i) { + *(buf++) = 0; + } + + /* set generator */ + if(xmlSecBnGetSize(&g) > xmlSecBnGetSize(&p)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "g", + XMLSEC_ERRORS_R_INVALID_SIZE, + "size=%d > %d", + xmlSecBnGetSize(&g), + xmlSecBnGetSize(&p)); + goto done; + } + xmlSecAssert2(xmlSecBnGetData(&g) != NULL, -1); + memcpy(buf, xmlSecBnGetData(&g), xmlSecBnGetSize(&g)); + buf += xmlSecBnGetSize(&g); + /* Pad with zeros */ + for(i = xmlSecBnGetSize(&g); i < xmlSecBnGetSize(&p); ++i) { + *(buf++) = 0; + } + + /* Public key */ + if(xmlSecBnGetSize(&y) > xmlSecBnGetSize(&p)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "y", + XMLSEC_ERRORS_R_INVALID_SIZE, + "size=%d > %d", + xmlSecBnGetSize(&y), + xmlSecBnGetSize(&p)); + goto done; + } + xmlSecAssert2(xmlSecBnGetData(&y) != NULL, -1); + memcpy(buf, xmlSecBnGetData(&y), xmlSecBnGetSize(&y)); + buf += xmlSecBnGetSize(&y); + /* Pad with zeros */ + for(i = xmlSecBnGetSize(&y); i < xmlSecBnGetSize(&p); ++i) { + *(buf++) = 0; + } + + /* Set seed to 0xFFFFFFFFF */ + seed = (DSSSEED*)buf; + memset(seed, 0, sizeof(*seed)); + seed->counter = 0xFFFFFFFF; /* SEED Counter set to 0xFFFFFFFF will cause seed to be ignored */ + + hProv = xmlSecMSCryptoFindProvider(xmlSecMSCryptoProviderInfo_Dss, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(hProv == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* import the key blob */ + if (!CryptImportKey(hProv, xmlSecBufferGetData(&blob), xmlSecBufferGetSize(&blob), 0, 0, &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptImportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecMSCryptoKeyDataAdoptKey(data, hProv, TRUE, hKey, 0, xmlSecKeyDataTypePublic); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + hProv = 0; + hKey = 0; + + ret = xmlSecKeySetValue(key, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + data = NULL; + + /* success */ + res = 0; + +done: + if (hKey != 0) { + CryptDestroyKey(hKey); + } + if (hProv != 0) { + CryptReleaseContext(hProv, 0); + } + if (data != NULL) { + xmlSecKeyDataDestroy(data); + } + + xmlSecBufferFinalize(&blob); + xmlSecBnFinalize(&p); + xmlSecBnFinalize(&q); + xmlSecBnFinalize(&g); + xmlSecBnFinalize(&y); + + return(res); +} + +static int +xmlSecMSCryptoKeyDataDsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + xmlSecBuffer buf; + DWORD dwBlobLen; + xmlSecByte* blob; + PUBLICKEYSTRUC* pubKeyStruc; + DSSPUBKEY *pubKey; + xmlSecSize keyLen, len; + xmlNodePtr cur; + int ret; + + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataDsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecMSCryptoKeyDataDsaId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(xmlSecKeyGetValue(key)); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(xmlSecMSCryptoKeyDataCtxGetKey(ctx) != 0, -1); + + if (!CryptExportKey(xmlSecMSCryptoKeyDataCtxGetKey(ctx), 0, PUBLICKEYBLOB, 0, NULL, &dwBlobLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptExportKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferInitialize(&buf, dwBlobLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%ld", dwBlobLen); + return(-1); + } + + blob = xmlSecBufferGetData(&buf); + if (!CryptExportKey(xmlSecMSCryptoKeyDataCtxGetKey(ctx), 0, PUBLICKEYBLOB, 0, blob, &dwBlobLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buf); + return(-1); + } + if (dwBlobLen < sizeof(PUBLICKEYSTRUC)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "blobLen=%ld", dwBlobLen); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* check PUBLICKEYSTRUC */ + pubKeyStruc = (PUBLICKEYSTRUC*)blob; + if(pubKeyStruc->bVersion != 0x02) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKeyStruc->bVersion=%d", pubKeyStruc->bVersion); + xmlSecBufferFinalize(&buf); + return(-1); + } + if(pubKeyStruc->bType != PUBLICKEYBLOB) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKeyStruc->bType=%d", (int)pubKeyStruc->bType); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* check DSSPUBKEY */ + pubKey = (DSSPUBKEY*)(blob + sizeof(PUBLICKEYSTRUC)); + if(pubKey->magic != 0x31535344) { /* DSS key magic */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKey->magic=0x%08lx", pubKey->magic); + xmlSecBufferFinalize(&buf); + return(-1); + } + keyLen = pubKey->bitlen / 8; + + /* we assume that sizeof(q) < 0x14, sizeof(g) <= sizeof(p) and sizeof(y) <= sizeof(p) */ + if (dwBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(DSSPUBKEY) + 3 * keyLen + 0x14 + sizeof(DSSSEED)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "blobLen=%ld; keyLen=%d", dwBlobLen, keyLen); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += sizeof(PUBLICKEYSTRUC) + sizeof(DSSPUBKEY); + + /* first is P node */ + cur = xmlSecAddChild(node, xmlSecNodeDSAP, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + ret = xmlSecBnBlobSetNodeValue(blob, keyLen, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += keyLen; + + /* next is Q node. */ + cur = xmlSecAddChild(node, xmlSecNodeDSAQ, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* we think that the size of q is 0x14, skip trailing zeros */ + for(len = 0x14; len > 0 && blob[len - 1] == 0; --len); + + ret = xmlSecBnBlobSetNodeValue(blob, len, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += 0x14; + + /* next is G node. */ + cur = xmlSecAddChild(node, xmlSecNodeDSAG, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* skip trailing zeros */ + for(len = keyLen; len > 0 && blob[len - 1] == 0; --len); + + ret = xmlSecBnBlobSetNodeValue(blob, len, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += keyLen; + + /* next is X node: not supported in MSCrypto */ + + /* next is Y node. */ + cur = xmlSecAddChild(node, xmlSecNodeDSAY, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* skip trailing zeros */ + for(len = keyLen; len > 0 && blob[len - 1] == 0; --len); + + ret = xmlSecBnBlobSetNodeValue(blob, len, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += keyLen; + + xmlSecBufferFinalize(&buf); + return(0); +} + +static int +xmlSecMSCryptoKeyDataDsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + HCRYPTPROV hProv = 0; + HCRYPTKEY hKey = 0; + DWORD dwKeySpec; + DWORD dwSize; + int res = -1; + int ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId), -1); + xmlSecAssert2(sizeBits > 0, -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + + hProv = xmlSecMSCryptoFindProvider(ctx->providers, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(hProv == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + dwKeySpec = AT_SIGNATURE; + dwSize = ((sizeBits << 16) | CRYPT_EXPORTABLE); + if (!CryptGenKey(hProv, CALG_DSS_SIGN, dwSize, &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CryptGenKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecMSCryptoKeyDataAdoptKey(data, hProv, TRUE, hKey, dwKeySpec, + xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + hProv = 0; + hKey = 0; + + /* success */ + res = 0; + +done: + if (hProv != 0) { + CryptReleaseContext(hProv, 0); + } + + if (hKey != 0) { + CryptDestroyKey(hKey); + } + + return(res); +} + +static xmlSecKeyDataType +xmlSecMSCryptoKeyDataDsaGetType(xmlSecKeyDataPtr data) { + return(xmlSecMSCryptoKeyDataGetType(data)); +} + +static xmlSecSize +xmlSecMSCryptoKeyDataDsaGetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId), 0); + + return xmlSecMSCryptoKeyDataGetSize(data); +} + +static void +xmlSecMSCryptoKeyDataDsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== dsa key: size = %d\n", + xmlSecMSCryptoKeyDataDsaGetSize(data)); +} + +static void +xmlSecMSCryptoKeyDataDsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<DSAKeyValue size=\"%d\" />\n", + xmlSecMSCryptoKeyDataDsaGetSize(data)); +} + +#endif /* XMLSEC_NO_DSA */ + + +#ifndef XMLSEC_NO_GOST +/************************************************************************** + * + * GOST2001 xml key representation processing. Contain errors. + * + *************************************************************************/ +static int xmlSecMSCryptoKeyDataGost2001Initialize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataGost2001Duplicate(xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecMSCryptoKeyDataGost2001Finalize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataGost2001XmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataGost2001XmlWrite(xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataGost2001Generate(xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecMSCryptoKeyDataGost2001GetType(xmlSecKeyDataPtr data); +static xmlSecSize xmlSecMSCryptoKeyDataGost2001GetSize(xmlSecKeyDataPtr data); +static void xmlSecMSCryptoKeyDataGost2001DebugDump(xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecMSCryptoKeyDataGost2001DebugXmlDump(xmlSecKeyDataPtr data, + FILE* output); + +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataGost2001Klass = { + sizeof(xmlSecKeyDataKlass), + xmlSecMSCryptoKeyDataSize, + + /* data */ + xmlSecNameGOST2001KeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefGOST2001KeyValue, /* const xmlChar* href; */ + xmlSecNodeGOST2001KeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecMSCryptoKeyDataGost2001Initialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecMSCryptoKeyDataGost2001Duplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecMSCryptoKeyDataGost2001Finalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + NULL, /* xmlSecMSCryptoKeyDataGost2001Generate,*/ /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecMSCryptoKeyDataGost2001GetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecMSCryptoKeyDataGost2001GetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + NULL, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + NULL, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecMSCryptoKeyDataGost2001DebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecMSCryptoKeyDataGost2001DebugXmlDump,/* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Gost[] = { + { MAGPRO_CSP, PROV_MAGPRO_GOST }, + { CRYPTOPRO_CSP, PROV_CRYPTOPRO_GOST }, + { NULL, 0 } +}; + +/** + * xmlSecMSCryptoKeyDataGost2001GetKlass: + * + * The GOST2001 key data klass. + * + * Returns: pointer to GOST2001 key data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataGost2001GetKlass(void) { + return(&xmlSecMSCryptoKeyDataGost2001Klass); +} + + +static int +xmlSecMSCryptoKeyDataGost2001Initialize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id), xmlSecKeyDataTypeUnknown); + + xmlSecMSCryptoKeyDataInitialize(data); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + ctx->providers = xmlSecMSCryptoProviderInfo_Gost; + return(0); +} + +static int +xmlSecMSCryptoKeyDataGost2001Duplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecMSCryptoKeyDataGost2001Id), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecMSCryptoKeyDataGost2001Id), -1); + + return(xmlSecMSCryptoKeyDataDuplicate(dst, src)); +} + +static void +xmlSecMSCryptoKeyDataGost2001Finalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id)); + + xmlSecMSCryptoKeyDataFinalize(data); +} + +static xmlSecKeyDataType +xmlSecMSCryptoKeyDataGost2001GetType(xmlSecKeyDataPtr data) { + return(xmlSecMSCryptoKeyDataGetType(data)); +} + +static xmlSecSize +xmlSecMSCryptoKeyDataGost2001GetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id), 0); + + return xmlSecMSCryptoKeyDataGetSize(data); +} + +static void +xmlSecMSCryptoKeyDataGost2001DebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== dsa key: size = %d\n", + xmlSecMSCryptoKeyDataGost2001GetSize(data)); +} + +static void +xmlSecMSCryptoKeyDataGost2001DebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id)); + xmlSecAssert(output != NULL); + + fprintf(output, "<GOST2001KeyValue size=\"%d\" />\n", + xmlSecMSCryptoKeyDataGost2001GetSize(data)); +} + +#endif /* XMLSEC_NO_GOST*/ |