summaryrefslogtreecommitdiff
path: root/src/mscrypto/certkeys.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscrypto/certkeys.c')
-rw-r--r--src/mscrypto/certkeys.c2615
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*/