summaryrefslogtreecommitdiff
path: root/src/mscng/x509.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscng/x509.c')
-rw-r--r--src/mscng/x509.c1423
1 files changed, 1423 insertions, 0 deletions
diff --git a/src/mscng/x509.c b/src/mscng/x509.c
new file mode 100644
index 00000000..4db2659e
--- /dev/null
+++ b/src/mscng/x509.c
@@ -0,0 +1,1423 @@
+/*
+ * XML Security Library (http://www.aleksey.com/xmlsec).
+ *
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2018 Miklos Vajna. All Rights Reserved.
+ */
+/**
+ * SECTION:x509
+ * @Short_description: X509 certificates implementation for Microsoft Cryptography API: Next Generation (CNG).
+ * @Stability: Stable
+ *
+ */
+
+#include "globals.h"
+
+#ifndef XMLSEC_NO_X509
+
+#include <string.h>
+
+#include <windows.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/keyinfo.h>
+#include <xmlsec/keysmngr.h>
+#include <xmlsec/x509.h>
+#include <xmlsec/base64.h>
+#include <xmlsec/bn.h>
+#include <xmlsec/errors.h>
+
+#include <xmlsec/mscng/crypto.h>
+#include <xmlsec/mscng/x509.h>
+#include <xmlsec/mscng/certkeys.h>
+
+typedef struct _xmlSecMSCngX509DataCtx xmlSecMSCngX509DataCtx,
+ *xmlSecMSCngX509DataCtxPtr;
+
+struct _xmlSecMSCngX509DataCtx {
+ HCERTSTORE hMemStore;
+ PCCERT_CONTEXT cert;
+};
+
+#define xmlSecMSCngX509DataSize \
+ (sizeof(xmlSecKeyData) + sizeof(xmlSecMSCngX509DataCtx))
+#define xmlSecMSCngX509DataGetCtx(data) \
+ ((xmlSecMSCngX509DataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData)))
+
+static int
+xmlSecMSCngKeyDataX509Initialize(xmlSecKeyDataPtr data) {
+ xmlSecMSCngX509DataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ ctx = xmlSecMSCngX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+ memset(ctx, 0, sizeof(xmlSecMSCngX509DataCtx));
+
+ ctx->hMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY,
+ 0,
+ 0,
+ CERT_STORE_CREATE_NEW_FLAG,
+ NULL);
+ if(ctx->hMemStore == 0) {
+ xmlSecMSCngLastError("CertOpenStore", xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ return(0);
+}
+
+static int
+xmlSecMSCngKeyDataX509Duplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) {
+ PCCERT_CONTEXT srcCert = NULL;
+ PCCERT_CONTEXT dstCert;
+ xmlSecMSCngX509DataCtxPtr srcCtx;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecMSCngKeyDataX509Id), -1);
+ srcCtx = xmlSecMSCngX509DataGetCtx(src);
+
+ /* duplicate the certificate store */
+ while((srcCert = CertEnumCertificatesInStore(srcCtx->hMemStore, srcCert)) != NULL) {
+ dstCert = CertDuplicateCertificateContext(srcCert);
+ if(dstCert == NULL) {
+ xmlSecMSCngLastError("CertDuplicateCertificateContext",
+ xmlSecKeyDataGetName(dst));
+ return(-1);
+ }
+
+ ret = xmlSecMSCngKeyDataX509AdoptCert(dst, dstCert);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptCert",
+ xmlSecKeyDataGetName(dst));
+ CertFreeCertificateContext(dstCert);
+ return(-1);
+ }
+ }
+
+ if(srcCtx->cert != NULL) {
+ /* have a key certificate, duplicate that */
+ dstCert = CertDuplicateCertificateContext(srcCtx->cert);
+ if(dstCert == NULL) {
+ xmlSecMSCngLastError("CertDuplicateCertificateContext",
+ xmlSecKeyDataGetName(dst));
+ return(-1);
+ }
+
+ ret = xmlSecMSCngKeyDataX509AdoptKeyCert(dst, dstCert);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptKeyCert",
+ xmlSecKeyDataGetName(dst));
+ CertFreeCertificateContext(dstCert);
+ return(-1);
+ }
+ }
+
+ return(0);
+}
+
+static void
+xmlSecMSCngKeyDataX509Finalize(xmlSecKeyDataPtr data) {
+ xmlSecMSCngX509DataCtxPtr ctx;
+
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id));
+
+ ctx = xmlSecMSCngX509DataGetCtx(data);
+ xmlSecAssert(ctx != NULL);
+
+ if(ctx->cert != NULL) {
+ if(!CertFreeCertificateContext(ctx->cert)) {
+ xmlSecMSCngLastError("CertFreeCertificateContext", NULL);
+ }
+ }
+
+ if(ctx->hMemStore != 0) {
+ if(!CertCloseStore(ctx->hMemStore, 0)) {
+ xmlSecMSCngLastError("CertCloseStore", NULL);
+ }
+ }
+
+ memset(ctx, 0, sizeof(xmlSecMSCngX509DataCtx));
+}
+
+static xmlSecKeyDataType
+xmlSecMSCngKeyDataX509GetType(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), xmlSecKeyDataTypeUnknown);
+
+ return(xmlSecKeyDataTypeUnknown);
+}
+
+static const xmlChar*
+xmlSecMSCngKeyDataX509GetIdentifier(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), NULL);
+
+ return(NULL);
+}
+
+/**
+ * xmlSecMSCngX509CertDerRead:
+ *
+ * The MSCng reader for the binary (DER-encoded) X509 certificate content.
+ */
+static PCCERT_CONTEXT
+xmlSecMSCngX509CertDerRead(const xmlSecByte* buf, xmlSecSize size) {
+ PCCERT_CONTEXT cert;
+
+ xmlSecAssert2(buf != NULL, NULL);
+ xmlSecAssert2(size > 0, NULL);
+
+ cert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, buf, size);
+ if(cert == NULL) {
+ xmlSecMSCngLastError("CertCreateCertificateContext", NULL);
+ return(NULL);
+ }
+
+ return(cert);
+}
+
+/**
+ * xmlSecMSCngX509CertBase64DerRead:
+ *
+ * The MSCng reader for the <X509Certificate> XML content.
+ */
+static PCCERT_CONTEXT
+xmlSecMSCngX509CertBase64DerRead(xmlChar* buf) {
+ int size;
+
+ xmlSecAssert2(buf != NULL, NULL);
+
+ /* in-place decoding */
+ size = xmlSecBase64Decode(buf, (xmlSecByte*)buf, xmlStrlen(buf));
+ if(size < 0) {
+ xmlSecInternalError("xmlSecBase64Decode", NULL);
+ return(NULL);
+ }
+
+ return(xmlSecMSCngX509CertDerRead((xmlSecByte*)buf, size));
+}
+
+
+int
+xmlSecMSCngKeyDataX509AdoptKeyCert(xmlSecKeyDataPtr data, PCCERT_CONTEXT cert) {
+ xmlSecMSCngX509DataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(cert != NULL, -1);
+
+ ctx = xmlSecMSCngX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ if(ctx->cert != NULL) {
+ CertFreeCertificateContext(ctx->cert);
+ }
+ ctx->cert = cert;
+
+ return(0);
+}
+
+int
+xmlSecMSCngKeyDataX509AdoptCert(xmlSecKeyDataPtr data, PCCERT_CONTEXT cert) {
+ xmlSecMSCngX509DataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(cert != NULL, -1);
+
+ ctx = xmlSecMSCngX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(ctx->hMemStore != 0, -1);
+
+ if(!CertAddCertificateContextToStore(ctx->hMemStore,
+ cert,
+ CERT_STORE_ADD_ALWAYS,
+ NULL)) {
+ xmlSecMSCngLastError("CertAddCertificateContextToStore",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ /* this just decrements the refcount, so won't free */
+ CertFreeCertificateContext(cert);
+ return(0);
+}
+
+/**
+ * xmlSecMSCngKeyDataX509AdoptCrl:
+ * @data: the pointer to X509 key data.
+ * @crl: the pointer to MSCng X509 CRL.
+ *
+ * Adds CRL to the X509 key data.
+ *
+ * Returns: 0 on success or a negative value if an error occurs.
+ */
+int
+xmlSecMSCngKeyDataX509AdoptCrl(xmlSecKeyDataPtr data, PCCRL_CONTEXT crl) {
+ xmlSecMSCngX509DataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(crl != 0, -1);
+
+ ctx = xmlSecMSCngX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(ctx->hMemStore != 0, -1);
+
+ if (!CertAddCRLContextToStore(ctx->hMemStore, crl, CERT_STORE_ADD_ALWAYS, NULL)) {
+ xmlSecMSCngLastError("CertAddCRLContextToStore",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ return(0);
+}
+
+/**
+ * xmlSecMSCngX509SubjectNameNodeRead:
+ *
+ * The MSCng reader for the <X509SubjectName> XML element.
+ */
+static int
+xmlSecMSCngX509SubjectNameNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataStorePtr store;
+ xmlChar* subject;
+ PCCERT_CONTEXT cert;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+ xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1);
+
+ store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecMSCngX509StoreId);
+ if(store == NULL) {
+ xmlSecInternalError("xmlSecKeysMngrGetDataStore",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ subject = xmlNodeGetContent(node);
+ if((subject == NULL) || (xmlSecIsEmptyString(subject) == 1)) {
+ if(subject != NULL) {
+ xmlFree(subject);
+ }
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecInvalidNodeContentError(node, xmlSecKeyDataGetName(data),
+ "empty");
+ return(-1);
+ }
+
+ return(0);
+ }
+
+ cert = xmlSecMSCngX509StoreFindCert(store, subject, NULL, NULL, NULL, keyInfoCtx);
+ if(cert == NULL) {
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CERT) != 0) {
+ xmlSecOtherError2(XMLSEC_ERRORS_R_CERT_NOT_FOUND,
+ xmlSecKeyDataGetName(data), "subject=%s",
+ xmlSecErrorsSafeString(subject));
+ xmlFree(subject);
+ return(-1);
+ }
+
+ xmlFree(subject);
+ return(0);
+ }
+
+ ret = xmlSecMSCngKeyDataX509AdoptCert(data, cert);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptCert",
+ xmlSecKeyDataGetName(data));
+ CertFreeCertificateContext(cert);
+ xmlFree(subject);
+ return(-1);
+ }
+
+ xmlFree(subject);
+ return(0);
+}
+/**
+ * xmlSecMSCngX509CertificateNodeRead:
+ *
+ * The MSCng reader for the <X509Certificate> XML element.
+ */
+static int
+xmlSecMSCngX509CertificateNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlChar* content;
+ PCCERT_CONTEXT cert;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ content = xmlNodeGetContent(node);
+ if((content == NULL) || (xmlSecIsEmptyString(content) == 1)) {
+ if(content != NULL) {
+ xmlFree(content);
+ }
+
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecInvalidNodeContentError(node, xmlSecKeyDataGetName(data),
+ "content is an empty string");
+ return(-1);
+ }
+
+ return(0);
+ }
+
+ cert = xmlSecMSCngX509CertBase64DerRead(content);
+ if(cert == NULL) {
+ xmlSecInternalError("xmlSecMSCngX509CertBase64DerRead",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ ret = xmlSecMSCngKeyDataX509AdoptCert(data, cert);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptCert",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+
+ }
+
+ xmlFree(content);
+ return(0);
+}
+
+/**
+ * xmlSecMSCngX509IssuerSerialNodeRead:
+ *
+ * The MSCng reader for the <X509IssuerSerial> XML element.
+ */
+static int
+xmlSecMSCngX509IssuerSerialNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataStorePtr store;
+ xmlNodePtr cur;
+ xmlChar* issuerName;
+ xmlChar* issuerSerial;
+ PCCERT_CONTEXT cert;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+ xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1);
+
+ store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecMSCngX509StoreId);
+ if(store == NULL) {
+ xmlSecInternalError("xmlSecKeysMngrGetDataStore",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ cur = xmlSecGetNextElementNode(node->children);
+ if(cur == NULL) {
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecNodeNotFoundError("xmlSecGetNextElementNode", node, NULL,
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ return(0);
+ }
+
+ /* handle X509IssuerName */
+ if(!xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerName, xmlSecDSigNs)) {
+ xmlSecInvalidNodeError(cur, xmlSecNodeX509IssuerName,
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ issuerName = xmlNodeGetContent(cur);
+ if(issuerName == NULL) {
+ xmlSecInvalidNodeContentError(cur, xmlSecKeyDataGetName(data),
+ "empty");
+ return(-1);
+ }
+
+ cur = xmlSecGetNextElementNode(cur->next);
+ if(cur == NULL) {
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecNodeNotFoundError("xmlSecGetNextElementNode", node, NULL,
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ return(0);
+ }
+
+ /* handle X509SerialNumber */
+ if(!xmlSecCheckNodeName(cur, xmlSecNodeX509SerialNumber, xmlSecDSigNs)) {
+ xmlSecInvalidNodeError(cur, xmlSecNodeX509SerialNumber,
+ xmlSecKeyDataGetName(data));
+ xmlFree(issuerName);
+ return(-1);
+ }
+
+ issuerSerial = xmlNodeGetContent(cur);
+ if(issuerSerial == NULL) {
+ xmlSecInvalidNodeContentError(cur, xmlSecKeyDataGetName(data),
+ "empty");
+ xmlFree(issuerSerial);
+ return(-1);
+ }
+
+ cur = xmlSecGetNextElementNode(cur->next);
+ if(cur != NULL) {
+ xmlSecUnexpectedNodeError(cur, xmlSecKeyDataGetName(data));
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(-1);
+ }
+
+ cert = xmlSecMSCngX509StoreFindCert(store, NULL, issuerName, issuerSerial,
+ NULL, keyInfoCtx);
+ if(cert == NULL) {
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CERT) != 0) {
+ xmlSecOtherError3(XMLSEC_ERRORS_R_CERT_NOT_FOUND, xmlSecKeyDataGetName(data),
+ "issuerName=%s;issuerSerial=%s",
+ xmlSecErrorsSafeString(issuerName),
+ xmlSecErrorsSafeString(issuerSerial));
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(-1);
+ }
+
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(0);
+ }
+
+ ret = xmlSecMSCngKeyDataX509AdoptCert(data, cert);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptCert",
+ xmlSecKeyDataGetName(data));
+ CertFreeCertificateContext(cert);
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(-1);
+ }
+
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(0);
+}
+
+/**
+ * xmlSecMSCngX509SKINodeRead:
+ *
+ * The MSCng reader for the <X509SKI> XML element.
+ */
+static int
+xmlSecMSCngX509SKINodeRead(xmlSecKeyDataPtr data, xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataStorePtr store;
+ xmlChar* ski;
+ PCCERT_CONTEXT cert;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+ xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1);
+
+ store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecMSCngX509StoreId);
+ if(store == NULL) {
+ xmlSecInternalError("xmlSecKeysMngrGetDataStore",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ ski = xmlNodeGetContent(node);
+ if((ski == NULL) || (xmlSecIsEmptyString(ski) == 1)) {
+ if(ski != NULL) {
+ xmlFree(ski);
+ }
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecInvalidNodeContentError(node, xmlSecKeyDataGetName(data),
+ "empty");
+ return(-1);
+ }
+ return(0);
+ }
+
+ cert = xmlSecMSCngX509StoreFindCert(store, NULL, NULL, NULL, ski, keyInfoCtx);
+ if(cert == NULL){
+ xmlFree(ski);
+
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CERT) != 0) {
+ xmlSecOtherError2(XMLSEC_ERRORS_R_CERT_NOT_FOUND, xmlSecKeyDataGetName(data),
+ "ski=%s", xmlSecErrorsSafeString(ski));
+ return(-1);
+ }
+ return(0);
+ }
+
+ ret = xmlSecMSCngKeyDataX509AdoptCert(data, cert);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptCert",
+ xmlSecKeyDataGetName(data));
+ CertFreeCertificateContext(cert);
+ xmlFree(ski);
+ return(-1);
+ }
+
+ xmlFree(ski);
+ return(0);
+}
+
+static PCCRL_CONTEXT
+xmlSecMSCngX509CrlDerRead(xmlSecByte* buf, xmlSecSize size,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ PCCRL_CONTEXT crl = NULL;
+
+ xmlSecAssert2(buf != NULL, NULL);
+ xmlSecAssert2(keyInfoCtx != NULL, NULL);
+ xmlSecAssert2(size > 0, NULL);
+
+ crl = CertCreateCRLContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, buf, size);
+
+ if(crl == NULL) {
+ xmlSecMSCngLastError("CertCreateCRLContext", NULL);
+ return(NULL);
+ }
+
+ return(crl);
+}
+
+static PCCRL_CONTEXT
+xmlSecMSCngX509CrlBase64DerRead(xmlChar* buf, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ int ret;
+
+ xmlSecAssert2(buf != NULL, NULL);
+
+ /* usual trick with base64 decoding in-place */
+ ret = xmlSecBase64Decode(buf, (xmlSecByte*)buf, xmlStrlen(buf));
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecBase64Decode", NULL);
+ return(NULL);
+ }
+
+ return(xmlSecMSCngX509CrlDerRead((xmlSecByte*)buf, ret, keyInfoCtx));
+}
+
+static int
+xmlSecMSCngX509CRLNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlChar *content;
+ PCCRL_CONTEXT crl;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ content = xmlNodeGetContent(node);
+ if((content == NULL) || (xmlSecIsEmptyString(content) == 1)) {
+ if(content != NULL) {
+ xmlFree(content);
+ }
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecInvalidNodeContentError(node, xmlSecKeyDataGetName(data), "empty");
+ return(-1);
+ }
+ return(0);
+ }
+
+ crl = xmlSecMSCngX509CrlBase64DerRead(content, keyInfoCtx);
+ if(crl == NULL) {
+ xmlSecInternalError("xmlSecMSCngX509CrlBase64DerRead",
+ xmlSecKeyDataGetName(data));
+ xmlFree(content);
+ return(-1);
+ }
+
+ ret = xmlSecMSCngKeyDataX509AdoptCrl(data, crl);
+ if (ret < 0) {
+ xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptCrl",
+ xmlSecKeyDataGetName(data));
+ xmlFree(content);
+ CertFreeCRLContext(crl);
+ return(-1);
+ }
+
+ xmlFree(content);
+ return(0);
+}
+
+/**
+ * xmlSecMSCngX509DataNodeRead:
+ *
+ * The MSCng reader for the <X509Data> XML element.
+ */
+static int
+xmlSecMSCngX509DataNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlNodePtr cur;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ for(cur = xmlSecGetNextElementNode(node->children);
+ cur != NULL;
+ cur = xmlSecGetNextElementNode(cur->next)) {
+ if(xmlSecCheckNodeName(cur, xmlSecNodeX509Certificate, xmlSecDSigNs)) {
+ ret = xmlSecMSCngX509CertificateNodeRead(data, cur, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509CertificateNodeRead",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SubjectName, xmlSecDSigNs)) {
+ ret = xmlSecMSCngX509SubjectNameNodeRead(data, cur, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509SubjectNameNodeRead",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerSerial, xmlSecDSigNs)) {
+ ret = xmlSecMSCngX509IssuerSerialNodeRead(data, cur, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509IssuerSerialNodeRead", NULL);
+ return(-1);
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SKI, xmlSecDSigNs)) {
+ ret = xmlSecMSCngX509SKINodeRead(data, cur, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509SKINodeRead", NULL);
+ return(-1);
+ }
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509CRL, xmlSecDSigNs)) {
+ ret = xmlSecMSCngX509CRLNodeRead(data, cur, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509CRLNodeRead",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+ } else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CHILD) != 0) {
+ xmlSecUnexpectedNodeError(cur, xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+/**
+ * xmlSecMSCngX509CertGetTime:
+ *
+ * Converts FILETIME timestamp into time_t. See
+ * <https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx>
+ * for details.
+ */
+static int
+xmlSecMSCngX509CertGetTime(FILETIME in, time_t* out) {
+ xmlSecAssert2(out != NULL, -1);
+
+ *out = in.dwHighDateTime;
+ *out <<= 32;
+ *out |= in.dwLowDateTime;
+ /* 100 nanoseconds -> seconds */
+ *out /= 10000;
+ /* 1601-01-01 epoch -> 1970-01-01 epoch */
+ *out -= 11644473600000;
+
+ return(0);
+}
+
+static int
+xmlSecMSCngKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr data,
+ xmlSecKeyPtr key, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecMSCngX509DataCtxPtr ctx;
+ xmlSecKeyDataStorePtr store;
+ PCCERT_CONTEXT cert;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id), -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+ xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1);
+
+ if(xmlSecKeyGetValue(key) != NULL) {
+ return(0);
+ }
+
+ ctx = xmlSecMSCngX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+ xmlSecAssert2(ctx->hMemStore != 0, -1);
+
+ if(ctx->cert != NULL) {
+ return(0);
+ }
+
+ store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecMSCngX509StoreId);
+ if(store == NULL) {
+ xmlSecInternalError("xmlSecKeysMngrGetDataStore",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ cert = xmlSecMSCngX509StoreVerify(store, ctx->hMemStore, keyInfoCtx);
+ if(cert != NULL) {
+ int ret;
+ PCCERT_CONTEXT certCopy;
+ xmlSecKeyDataPtr keyValue = NULL;
+
+ ctx->cert = CertDuplicateCertificateContext(cert);
+ if(ctx->cert == NULL) {
+ xmlSecMSCngLastError("CertDuplicateCertificateContext",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ /* copy the certificate, so it can be adopted according to the key data
+ * type */
+ certCopy = CertDuplicateCertificateContext(ctx->cert);
+ if(certCopy == NULL) {
+ xmlSecMSCngLastError("CertDuplicateCertificateContext",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ if((keyInfoCtx->keyReq.keyType & xmlSecKeyDataTypePrivate) != 0) {
+ keyValue = xmlSecMSCngCertAdopt(certCopy, xmlSecKeyDataTypePrivate);
+ if(keyValue == NULL) {
+ xmlSecInternalError("xmlSecMSCngCertAdopt",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+ } else if((keyInfoCtx->keyReq.keyType & xmlSecKeyDataTypePublic) != 0) {
+ keyValue = xmlSecMSCngCertAdopt(certCopy, xmlSecKeyDataTypePublic);
+ if(keyValue == NULL) {
+ xmlSecInternalError("xmlSecMSCngCertAdopt",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+ }
+
+ /* verify that keyValue matches the key requirements */
+ if(xmlSecKeyReqMatchKeyValue(&(keyInfoCtx->keyReq), keyValue) != 1) {
+ xmlSecInternalError("xmlSecKeyReqMatchKeyValue",
+ xmlSecKeyDataGetName(data));
+ xmlSecKeyDataDestroy(keyValue);
+ return(-1);
+ }
+
+ ret = xmlSecKeySetValue(key, keyValue);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecKeySetValue",
+ xmlSecKeyDataGetName(data));
+ xmlSecKeyDataDestroy(keyValue);
+ return(-1);
+ }
+
+ ret = xmlSecMSCngX509CertGetTime(ctx->cert->pCertInfo->NotBefore,
+ &(key->notValidBefore));
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509CertGetTime",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+
+ ret = xmlSecMSCngX509CertGetTime(ctx->cert->pCertInfo->NotAfter,
+ &(key->notValidAfter));
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509CertGetTime",
+ xmlSecKeyDataGetName(data));
+ return(-1);
+ }
+ } else if((keyInfoCtx->flags &
+ XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_INVALID_CERT) != 0) {
+ xmlSecOtherError(XMLSEC_ERRORS_R_CERT_NOT_FOUND,
+ xmlSecKeyDataGetName(data), NULL);
+ return(-1);
+ }
+
+ return(0);
+}
+
+static int
+xmlSecMSCngKeyDataX509XmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key,
+ xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataPtr data;
+ int ret;
+
+ xmlSecAssert2(id == xmlSecMSCngKeyDataX509Id, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ data = xmlSecKeyEnsureData(key, id);
+ if(data == NULL) {
+ xmlSecInternalError("xmlSecKeyEnsureData",
+ xmlSecKeyDataKlassGetName(id));
+ return(-1);
+ }
+
+ ret = xmlSecMSCngX509DataNodeRead(data, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509DataNodeRead",
+ xmlSecKeyDataKlassGetName(id));
+ return(-1);
+ }
+
+ ret = xmlSecMSCngKeyDataX509VerifyAndExtractKey(data, key, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngKeyDataX509VerifyAndExtractKey",
+ xmlSecKeyDataKlassGetName(id));
+ return(-1);
+ }
+
+ return(0);
+}
+
+static int
+xmlSecMSCngX509CertificateNodeWrite(PCCERT_CONTEXT cert, xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlChar* buf;
+ xmlNodePtr child;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(cert->pbCertEncoded != NULL, -1);
+ xmlSecAssert2(cert->cbCertEncoded > 0, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ buf = xmlSecBase64Encode(cert->pbCertEncoded, cert->cbCertEncoded,
+ keyInfoCtx->base64LineSize);
+ if(buf == NULL) {
+ xmlSecInternalError("xmlSecBase64Encode", NULL);
+ return(-1);
+ }
+
+ child = xmlSecEnsureEmptyChild(node, xmlSecNodeX509Certificate, xmlSecDSigNs);
+ if(child == NULL) {
+ xmlSecInternalError("xmlSecEnsureEmptyChild", NULL);
+ xmlFree(buf);
+ return(-1);
+ }
+
+ xmlNodeSetContent(child, buf);
+ xmlFree(buf);
+
+ return(0);
+}
+
+static xmlChar*
+xmlSecMSCngX509NameWrite(PCERT_NAME_BLOB nm) {
+ LPTSTR resT = NULL;
+ xmlChar *res = NULL;
+ DWORD csz;
+
+
+ xmlSecAssert2(nm->pbData != NULL, NULL);
+ xmlSecAssert2(nm->cbData > 0, NULL);
+
+ csz = CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, nm, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, NULL, 0);
+ if(csz <= 0) {
+ xmlSecMSCngLastError("CertNameToStr", NULL);
+ return(NULL);
+ }
+
+ resT = (LPTSTR)xmlMalloc(sizeof(TCHAR) * (csz + 1));
+ if (NULL == resT) {
+ xmlSecMallocError(sizeof(TCHAR) * (csz + 1), NULL);
+ return (NULL);
+ }
+
+ csz = CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, nm, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, resT, csz + 1);
+ if (csz <= 0) {
+ xmlSecMSCngLastError("CertNameToStr", NULL);
+ xmlFree(resT);
+ return(NULL);
+ }
+
+ res = xmlSecWin32ConvertTstrToUtf8(resT);
+ if (NULL == res) {
+ xmlSecInternalError("xmlSecWin32ConvertTstrToUtf8", NULL);
+ xmlFree(resT);
+ return(NULL);
+ }
+
+ xmlFree(resT);
+ return(res);
+}
+
+static int
+xmlSecMSCngX509SubjectNameNodeWrite(PCCERT_CONTEXT cert, xmlNodePtr node) {
+ xmlChar* buf = NULL;
+ xmlNodePtr cur = NULL;
+ int ret;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+
+ buf = xmlSecMSCngX509NameWrite(&(cert->pCertInfo->Subject));
+ if(buf == NULL) {
+ xmlSecInternalError("xmlSecMSCngX509NameWrite", NULL);
+ return(-1);
+ }
+
+ cur = xmlSecEnsureEmptyChild(node, xmlSecNodeX509SubjectName, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecInternalError("xmlSecEnsureEmptyChild", NULL);
+ xmlFree(buf);
+ return(-1);
+ }
+
+ ret = xmlSecNodeEncodeAndSetContent(cur, buf);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecNodeEncodeAndSetContent", NULL);
+ xmlFree(buf);
+ return(-1);
+ }
+
+ /* done */
+ xmlFree(buf);
+ return(0);
+}
+
+static int
+xmlSecMSCngASN1IntegerWrite(xmlNodePtr node, PCRYPT_INTEGER_BLOB num) {
+ xmlSecBn bn;
+ int ret;
+
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(num != NULL, -1);
+
+ ret = xmlSecBnInitialize(&bn, num->cbData + 1);
+ if(ret < 0) {
+ xmlSecInternalError2("xmlSecBnInitialize", NULL, "size=%ld",
+ num->cbData + 1);
+ return(-1);
+ }
+
+ ret = xmlSecBnSetData(&bn, num->pbData, num->cbData);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecBnSetData", NULL);
+ xmlSecBnFinalize(&bn);
+ return(-1);
+ }
+
+ /* SerialNumber is little-endian, see <https://msdn.microsoft.com/en-us/library/windows/desktop/aa377200(v=vs.85).aspx>.
+ * xmldsig wants big-endian, so enable reversing */
+ ret = xmlSecBnSetNodeValue(&bn, node, xmlSecBnDec, 1, 0);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecBnSetNodeValue", NULL);
+ xmlSecBnFinalize(&bn);
+ return(-1);
+ }
+
+ xmlSecBnFinalize(&bn);
+ return(0);
+}
+
+static int
+xmlSecMSCngX509IssuerSerialNodeWrite(PCCERT_CONTEXT cert, xmlNodePtr node) {
+ xmlNodePtr cur;
+ xmlNodePtr issuerNameNode;
+ xmlNodePtr issuerNumberNode;
+ xmlChar* buf;
+ int ret;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+
+ /* create xml nodes */
+ cur = xmlSecEnsureEmptyChild(node, xmlSecNodeX509IssuerSerial, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecInternalError("xmlSecEnsureEmptyChild", NULL);
+ return(-1);
+ }
+
+ issuerNameNode = xmlSecEnsureEmptyChild(cur, xmlSecNodeX509IssuerName, xmlSecDSigNs);
+ if(issuerNameNode == NULL) {
+ xmlSecInternalError("xmlSecEnsureEmptyChild", NULL);
+ return(-1);
+ }
+
+ issuerNumberNode = xmlSecEnsureEmptyChild(cur, xmlSecNodeX509SerialNumber, xmlSecDSigNs);
+ if(issuerNumberNode == NULL) {
+ xmlSecInternalError("xmlSecEnsureEmptyChild", NULL);
+ return(-1);
+ }
+
+ /* write data */
+ buf = xmlSecMSCngX509NameWrite(&(cert->pCertInfo->Issuer));
+ if(buf == NULL) {
+ xmlSecInternalError("xmlSecMSCngX509NameWrite", NULL);
+ return(-1);
+ }
+
+ ret = xmlSecNodeEncodeAndSetContent(issuerNameNode, buf);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecNodeEncodeAndSetContent", NULL);
+ xmlFree(buf);
+ return(-1);
+ }
+
+ xmlFree(buf);
+
+ ret = xmlSecMSCngASN1IntegerWrite(issuerNumberNode, &(cert->pCertInfo->SerialNumber));
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngASN1IntegerWrite", NULL);
+ return(-1);
+ }
+ return(0);
+}
+
+static xmlChar*
+xmlSecMSCngX509SKIWrite(PCCERT_CONTEXT cert) {
+ xmlChar *res = NULL;
+ DWORD dwSize;
+ BYTE *bSKI = NULL;
+ PCERT_EXTENSION pCertExt;
+
+ xmlSecAssert2(cert != NULL, NULL);
+
+ /* First check if the SKI extension actually exists, otherwise we get a SHA1 hash of the cert */
+ pCertExt = CertFindExtension(szOID_SUBJECT_KEY_IDENTIFIER, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension);
+ if (pCertExt == NULL) {
+ xmlSecMSCngLastError("CertFindExtension", NULL);
+ return (NULL);
+ }
+
+ if (!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &dwSize) || dwSize < 1) {
+ xmlSecMSCngLastError("CertGetCertificateContextProperty", NULL);
+ return (NULL);
+ }
+ bSKI = xmlMalloc(dwSize);
+ if (bSKI == NULL) {
+ xmlSecMallocError(dwSize, NULL);
+ return (NULL);
+ }
+
+ if (!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, bSKI, &dwSize)) {
+ xmlSecMSCngLastError("CertGetCertificateContextProperty", NULL);
+ xmlFree(bSKI);
+ return (NULL);
+ }
+
+ if (bSKI == NULL) {
+ return(NULL);
+ }
+
+ res = xmlSecBase64Encode(bSKI, dwSize, 0);
+ if(res == NULL) {
+ xmlSecInternalError("xmlSecBase64Encode", NULL);
+ xmlFree(bSKI);
+ return(NULL);
+ }
+ xmlFree(bSKI);
+
+ return(res);
+}
+
+static int
+xmlSecMSCngX509SKINodeWrite(PCCERT_CONTEXT cert, xmlNodePtr node) {
+ xmlChar *buf = NULL;
+ xmlNodePtr cur = NULL;
+ int ret;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+
+ buf = xmlSecMSCngX509SKIWrite(cert);
+ if(buf == NULL) {
+ xmlSecInternalError("xmlSecMSCngX509SKIWrite", NULL);
+ return(-1);
+ }
+
+ cur = xmlSecEnsureEmptyChild(node, xmlSecNodeX509SKI, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecInternalError("xmlSecEnsureEmptyChild", NULL);
+ xmlFree(buf);
+ return(-1);
+ }
+
+ ret = xmlSecNodeEncodeAndSetContent(cur, buf);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecNodeEncodeAndSetContent", NULL);
+ xmlFree(buf);
+ return(-1);
+ }
+
+ xmlFree(buf);
+ return(0);
+}
+
+static int
+xmlSecMSCngX509CRLNodeWrite(PCCRL_CONTEXT crl, xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecAssert2(crl != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ xmlSecNotImplementedError(NULL);
+
+ return(-1);
+}
+
+static int
+xmlSecMSCngKeyDataX509XmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key,
+ xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ int content;
+ xmlSecKeyDataPtr keyData;
+ xmlSecMSCngX509DataCtxPtr x509DataCtx;
+ PCCERT_CONTEXT cert = NULL;
+ HCERTSTORE certs;
+ PCCRL_CONTEXT crlCtx = NULL;
+ int ret;
+
+ xmlSecAssert2(id == xmlSecMSCngKeyDataX509Id, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ content = xmlSecX509DataGetNodeContent(node, keyInfoCtx);
+ if(content < 0) {
+ xmlSecInternalError("xmlSecX509DataGetNodeContent",
+ xmlSecKeyDataKlassGetName(id));
+ return(-1);
+ }
+ if(content == 0) {
+ /* no content -> writer the default */
+ content = XMLSEC_X509DATA_DEFAULT;
+ }
+
+ keyData = xmlSecKeyGetData(key, id);
+ if(keyData == NULL) {
+ /* nothing to do */
+ return(0);
+ }
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(keyData, xmlSecMSCngKeyDataX509Id), -1);
+ x509DataCtx = xmlSecMSCngX509DataGetCtx(keyData);
+ certs = x509DataCtx->hMemStore;
+
+ /* write certificates */
+ while((cert = CertEnumCertificatesInStore(certs, cert)) != NULL) {
+ if((content & XMLSEC_X509DATA_CERTIFICATE_NODE) != 0) {
+ ret = xmlSecMSCngX509CertificateNodeWrite(cert, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509CertificateNodeWrite",
+ xmlSecKeyDataKlassGetName(id));
+ return(-1);
+ }
+ }
+
+ if((content & XMLSEC_X509DATA_SUBJECTNAME_NODE) != 0) {
+ ret = xmlSecMSCngX509SubjectNameNodeWrite(cert, node);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509SubjectNameNodeWrite",
+ xmlSecKeyDataKlassGetName(id));
+ return(-1);
+ }
+ }
+
+ if((content & XMLSEC_X509DATA_ISSUERSERIAL_NODE) != 0) {
+ ret = xmlSecMSCngX509IssuerSerialNodeWrite(cert, node);
+ if(ret< 0) {
+ xmlSecInternalError("xmlSecMSCngX509IssuerSerialNodeWrite",
+ xmlSecKeyDataKlassGetName(id));
+ return(-1);
+ }
+ }
+
+ if((content & XMLSEC_X509DATA_SKI_NODE) != 0) {
+ ret = xmlSecMSCngX509SKINodeWrite(cert, node);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509SKINodeWrite",
+ xmlSecKeyDataKlassGetName(id));
+ return(-1);
+ }
+ }
+ }
+
+ /* write CRLs */
+ while((crlCtx = CertEnumCRLsInStore(certs, crlCtx)) != NULL) {
+ ret = xmlSecMSCngX509CRLNodeWrite(crlCtx, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngX509CRLNodeWrite",
+ xmlSecKeyDataKlassGetName(id));
+ return(-1);
+ }
+ }
+
+ return(0);
+}
+
+static void
+xmlSecMSCngKeyDataX509DebugDump(xmlSecKeyDataPtr data, FILE* output) {
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id));
+ xmlSecAssert(output != NULL);
+
+ xmlSecNotImplementedError(NULL);
+}
+
+static void
+xmlSecMSCngKeyDataX509DebugXmlDump(xmlSecKeyDataPtr data, FILE* output) {
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCngKeyDataX509Id));
+ xmlSecAssert(output != NULL);
+
+ xmlSecNotImplementedError(NULL);
+}
+
+static xmlSecKeyDataKlass xmlSecMSCngKeyDataX509Klass = {
+ sizeof(xmlSecKeyDataKlass),
+ xmlSecMSCngX509DataSize,
+
+ /* data */
+ xmlSecNameX509Data,
+ xmlSecKeyDataUsageKeyInfoNode | xmlSecKeyDataUsageRetrievalMethodNodeXml,
+ /* xmlSecKeyDataUsage usage; */
+ xmlSecHrefX509Data, /* const xmlChar* href; */
+ xmlSecNodeX509Data, /* const xmlChar* dataNodeName; */
+ xmlSecDSigNs, /* const xmlChar* dataNodeNs; */
+
+ /* constructors/destructor */
+ xmlSecMSCngKeyDataX509Initialize, /* xmlSecKeyDataInitializeMethod initialize; */
+ xmlSecMSCngKeyDataX509Duplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */
+ xmlSecMSCngKeyDataX509Finalize, /* xmlSecKeyDataFinalizeMethod finalize; */
+ NULL, /* xmlSecKeyDataGenerateMethod generate; */
+
+ /* get info */
+ xmlSecMSCngKeyDataX509GetType, /* xmlSecKeyDataGetTypeMethod getType; */
+ NULL, /* xmlSecKeyDataGetSizeMethod getSize; */
+ xmlSecMSCngKeyDataX509GetIdentifier, /* xmlSecKeyDataGetIdentifier getIdentifier; */
+
+ /* read/write */
+ xmlSecMSCngKeyDataX509XmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */
+ xmlSecMSCngKeyDataX509XmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */
+ NULL, /* xmlSecKeyDataBinReadMethod binRead; */
+ NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */
+
+ /* debug */
+ xmlSecMSCngKeyDataX509DebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */
+ xmlSecMSCngKeyDataX509DebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+ /* reserved for the future */
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+/**
+ * xmlSecMSCngKeyDataX509GetKlass:
+ *
+ * The MSCng X509 key data klass.
+ *
+ * Returns: the X509 data klass.
+ */
+xmlSecKeyDataId
+xmlSecMSCngKeyDataX509GetKlass(void) {
+ return(&xmlSecMSCngKeyDataX509Klass);
+}
+
+/**************************************************************************
+ *
+ * Raw X509 Certificate processing
+ *
+ *
+ *************************************************************************/
+static int
+xmlSecMSCngKeyDataRawX509CertBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key,
+ const xmlSecByte* buf, xmlSecSize bufSize,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataPtr data;
+ PCCERT_CONTEXT cert;
+ int ret;
+
+ xmlSecAssert2(id == xmlSecMSCngKeyDataRawX509CertId, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(buf != NULL, -1);
+ xmlSecAssert2(bufSize > 0, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ cert = xmlSecMSCngX509CertDerRead(buf, bufSize);
+ if(cert == NULL) {
+ xmlSecInternalError("xmlSecMSCngX509CertDerRead", NULL);
+ return(-1);
+ }
+
+ data = xmlSecKeyEnsureData(key, xmlSecMSCngKeyDataX509Id);
+ if(data == NULL) {
+ xmlSecInternalError("xmlSecKeyEnsureData",
+ xmlSecKeyDataKlassGetName(id));
+ CertFreeCertificateContext(cert);
+ return(-1);
+ }
+
+ ret = xmlSecMSCngKeyDataX509AdoptCert(data, cert);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngKeyDataX509AdoptCert",
+ xmlSecKeyDataKlassGetName(id));
+ CertFreeCertificateContext(cert);
+ return(-1);
+ }
+
+ ret = xmlSecMSCngKeyDataX509VerifyAndExtractKey(data, key, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecInternalError("xmlSecMSCngKeyDataX509VerifyAndExtractKey",
+ xmlSecKeyDataKlassGetName(id));
+ return(-1);
+ }
+
+ return(0);
+}
+
+static xmlSecKeyDataKlass xmlSecMSCngKeyDataRawX509CertKlass = {
+ sizeof(xmlSecKeyDataKlass),
+ sizeof(xmlSecKeyData),
+
+ /* data */
+ xmlSecNameRawX509Cert,
+ xmlSecKeyDataUsageRetrievalMethodNodeBin,
+ /* xmlSecKeyDataUsage usage; */
+ xmlSecHrefRawX509Cert, /* const xmlChar* href; */
+ NULL, /* const xmlChar* dataNodeName; */
+ xmlSecDSigNs, /* const xmlChar* dataNodeNs; */
+
+ /* constructors/destructor */
+ NULL, /* xmlSecKeyDataInitializeMethod initialize; */
+ NULL, /* xmlSecKeyDataDuplicateMethod duplicate; */
+ NULL, /* xmlSecKeyDataFinalizeMethod finalize; */
+ NULL, /* xmlSecKeyDataGenerateMethod generate; */
+
+ /* get info */
+ NULL, /* xmlSecKeyDataGetTypeMethod getType; */
+ NULL, /* xmlSecKeyDataGetSizeMethod getSize; */
+ NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */
+
+ /* read/write */
+ NULL, /* xmlSecKeyDataXmlReadMethod xmlRead; */
+ NULL, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */
+ xmlSecMSCngKeyDataRawX509CertBinRead, /* xmlSecKeyDataBinReadMethod binRead; */
+ NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */
+
+ /* debug */
+ NULL, /* xmlSecKeyDataDebugDumpMethod debugDump; */
+ NULL, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+ /* reserved for the future */
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+/**
+ * xmlSecMSCngKeyDataRawX509CertGetKlass:
+ *
+ * The raw X509 certificates key data klass.
+ *
+ * Returns: raw X509 certificates key data klass.
+ */
+xmlSecKeyDataId
+xmlSecMSCngKeyDataRawX509CertGetKlass(void) {
+ return(&xmlSecMSCngKeyDataRawX509CertKlass);
+}
+
+#endif /* XMLSEC_NO_X509 */