[xmlsec] added X509Data support to xmlsec-gnutls
- From: Aleksey Sanin <aleksey src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [xmlsec] added X509Data support to xmlsec-gnutls
- Date: Mon, 24 May 2010 22:35:58 +0000 (UTC)
commit 178c617e5079774ce7b9dfc72e74596179471b55
Author: Aleksey Sanin <aleksey aleksey com>
Date: Sun May 23 19:08:25 2010 -0700
added X509Data support to xmlsec-gnutls
ChangeLog | 3 +
include/xmlsec/gnutls/Makefile.am | 1 +
include/xmlsec/gnutls/x509.h | 99 +++
src/gnutls/Makefile.am | 4 +
src/gnutls/app.c | 200 ++++-
src/gnutls/crypto.c | 39 +-
src/gnutls/globals.h | 3 +
src/gnutls/x509.c | 1644 +++++++++++++++++++++++++++++++++++++
src/gnutls/x509utils.c | 562 +++++++++++++
src/gnutls/x509utils.h | 65 ++
src/gnutls/x509vfy.c | 541 ++++++++++++
11 files changed, 3128 insertions(+), 33 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index df2422d..08c2365 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+2010-05-23 Aleksey Sanin <aleksey aleksey com>
+ * Added X509Data support to xmlsec-gnutls
+
2010-05-12 Aleksey Sanin <aleksey aleksey com>
* Several patches from Roumen: support NSS/NSPR from seamonkey
package; reorder libxmlsec as dep. lib for mingw; fix gcrypt/src/asn1.h
diff --git a/include/xmlsec/gnutls/Makefile.am b/include/xmlsec/gnutls/Makefile.am
index 45b03d6..78235c4 100644
--- a/include/xmlsec/gnutls/Makefile.am
+++ b/include/xmlsec/gnutls/Makefile.am
@@ -6,6 +6,7 @@ xmlsecgnutlsinc_HEADERS = \
app.h \
crypto.h \
symbols.h \
+x509.h \
$(NULL)
install-exec-hook:
diff --git a/include/xmlsec/gnutls/x509.h b/include/xmlsec/gnutls/x509.h
new file mode 100644
index 0000000..f18a864
--- /dev/null
+++ b/include/xmlsec/gnutls/x509.h
@@ -0,0 +1,99 @@
+/**
+ * XMLSec library
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2010 Aleksey Sanin <aleksey aleksey com>
+ */
+#ifndef __XMLSEC_GNUTLS_X509_H__
+#define __XMLSEC_GNUTLS_X509_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef XMLSEC_NO_X509
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/transforms.h>
+
+
+/**************************************************************************
+ *
+ * X509 Key Data
+ *
+ *****************************************************************************/
+/**
+ * xmlSecGnuTLSKeyDataX509Id:
+ *
+ * The GnuTLS X509 data klass.
+ */
+#define xmlSecGnuTLSKeyDataX509Id \
+ xmlSecGnuTLSKeyDataX509GetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecKeyDataId xmlSecGnuTLSKeyDataX509GetKlass (void);
+
+XMLSEC_CRYPTO_EXPORT gnutls_x509_crt_t xmlSecGnuTLSKeyDataX509GetKeyCert (xmlSecKeyDataPtr data);
+XMLSEC_CRYPTO_EXPORT int xmlSecGnuTLSKeyDataX509AdoptKeyCert (xmlSecKeyDataPtr data,
+ gnutls_x509_crt_t cert);
+XMLSEC_CRYPTO_EXPORT int xmlSecGnuTLSKeyDataX509AdoptCert (xmlSecKeyDataPtr data,
+ gnutls_x509_crt_t cert);
+XMLSEC_CRYPTO_EXPORT gnutls_x509_crt_t xmlSecGnuTLSKeyDataX509GetCert (xmlSecKeyDataPtr data,
+ xmlSecSize pos);
+XMLSEC_CRYPTO_EXPORT xmlSecSize xmlSecGnuTLSKeyDataX509GetCertsSize (xmlSecKeyDataPtr data);
+XMLSEC_CRYPTO_EXPORT xmlSecKeyDataPtr xmlSecGnuTLSX509CertGetKey (gnutls_x509_crt_t cert);
+
+/**************************************************************************
+ *
+ * X509 raw cert
+ *
+ *****************************************************************************/
+/**
+ * xmlSecGnuTLSKeyDataRawX509CertId:
+ *
+ * The GnuTLS raw X509 certificate klass.
+ */
+#define xmlSecGnuTLSKeyDataRawX509CertId \
+ xmlSecGnuTLSKeyDataRawX509CertGetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecKeyDataId xmlSecGnuTLSKeyDataRawX509CertGetKlass (void);
+
+/**************************************************************************
+ *
+ * X509 certs store
+ *
+ *****************************************************************************/
+/**
+ * xmlSecGnuTLSX509StoreId:
+ *
+ * The GnuTLS X509 store klass.
+ */
+#define xmlSecGnuTLSX509StoreId \
+ xmlSecGnuTLSX509StoreGetKlass()
+XMLSEC_CRYPTO_EXPORT xmlSecKeyDataStoreId xmlSecGnuTLSX509StoreGetKlass (void);
+XMLSEC_CRYPTO_EXPORT gnutls_x509_crt_t xmlSecGnuTLSX509StoreFindCert (const xmlSecKeyDataStorePtr store,
+ const xmlChar *subjectName,
+ const xmlChar *issuerName,
+ const xmlChar *issuerSerial,
+ const xmlChar *ski,
+ const xmlSecKeyInfoCtx* keyInfoCtx);
+XMLSEC_CRYPTO_EXPORT gnutls_x509_crt_t xmlSecGnuTLSX509StoreVerify (xmlSecKeyDataStorePtr store,
+ xmlSecPtrListPtr certs,
+ const xmlSecKeyInfoCtx* keyInfoCtx);
+XMLSEC_CRYPTO_EXPORT int xmlSecGnuTLSX509StoreAdoptCert (xmlSecKeyDataStorePtr store,
+ gnutls_x509_crt_t cert,
+ xmlSecKeyDataType type);
+
+
+
+
+#endif /* XMLSEC_NO_X509 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __XMLSEC_GNUTLS_X509_H__ */
diff --git a/src/gnutls/Makefile.am b/src/gnutls/Makefile.am
index bfbf2d8..84ce637 100644
--- a/src/gnutls/Makefile.am
+++ b/src/gnutls/Makefile.am
@@ -29,6 +29,10 @@ libxmlsec1_gnutls_la_SOURCES =\
symkeys.c \
asymkeys.c \
signatures.c \
+ x509utils.h \
+ x509utils.c \
+ x509.c \
+ x509vfy.c \
globals.h \
$(NULL)
diff --git a/src/gnutls/app.c b/src/gnutls/app.c
index d936b8a..f01598b 100644
--- a/src/gnutls/app.c
+++ b/src/gnutls/app.c
@@ -11,6 +11,8 @@
#include <string.h>
#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/pkcs12.h>
#include <xmlsec/xmlsec.h>
#include <xmlsec/keys.h>
@@ -41,15 +43,15 @@
*/
int
xmlSecGnuTLSAppInit(const char* config) {
- int ret;
+ int err;
- ret = gnutls_global_init();
- if(ret != 0) {
+ err = gnutls_global_init();
+ if(err != GNUTLS_E_SUCCESS) {
xmlSecError(XMLSEC_ERRORS_HERE,
NULL,
"gnutls_global_init",
XMLSEC_ERRORS_R_CRYPTO_FAILED,
- "ret=%d", ret);
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
return(-1);
}
@@ -89,10 +91,23 @@ xmlSecGnuTLSAppKeyLoad(const char *filename, xmlSecKeyDataFormat format,
const char *pwd,
void* pwdCallback,
void* pwdCallbackCtx) {
+ xmlSecKeyPtr key;
+
xmlSecAssert2(filename != NULL, NULL);
xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL);
- return(xmlSecGCryptAppKeyLoad(filename, format, pwd, pwdCallback, pwdCallbackCtx));
+ switch(format) {
+#ifndef XMLSEC_NO_X509
+ case xmlSecKeyDataFormatPkcs12:
+ key = xmlSecGnuTLSAppPkcs12Load(filename, pwd, pwdCallback, pwdCallbackCtx);
+ break;
+#endif /* XMLSEC_NO_X509 */
+ default:
+ key = xmlSecGCryptAppKeyLoad(filename, format, pwd, pwdCallback, pwdCallbackCtx);
+ break;
+ }
+
+ return(key);
}
/**
@@ -112,10 +127,22 @@ xmlSecKeyPtr
xmlSecGnuTLSAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize,
xmlSecKeyDataFormat format, const char *pwd,
void* pwdCallback, void* pwdCallbackCtx) {
+ xmlSecKeyPtr key;
+
xmlSecAssert2(data != NULL, NULL);
xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL);
- return(xmlSecGCryptAppKeyLoadMemory(data, dataSize, format, pwd, pwdCallback, pwdCallbackCtx));
+ switch(format) {
+#ifndef XMLSEC_NO_X509
+ case xmlSecKeyDataFormatPkcs12:
+ key = xmlSecGnuTLSAppPkcs12LoadMemory(data, dataSize, pwd, pwdCallback, pwdCallbackCtx);
+ break;
+#endif /* XMLSEC_NO_X509 */
+ default:
+ key = xmlSecGCryptAppKeyLoadMemory(data, dataSize, format, pwd, pwdCallback, pwdCallbackCtx);
+ break;
+ }
+ return(key);
}
#ifndef XMLSEC_NO_X509
@@ -133,17 +160,53 @@ xmlSecGnuTLSAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize,
int
xmlSecGnuTLSAppKeyCertLoad(xmlSecKeyPtr key, const char* filename,
xmlSecKeyDataFormat format) {
+ xmlSecBuffer buffer;
+ int ret;
+
xmlSecAssert2(key != NULL, -1);
xmlSecAssert2(filename != NULL, -1);
xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1);
- /* TODO */
- xmlSecError(XMLSEC_ERRORS_HERE,
- NULL,
- "xmlSecGnuTLSAppKeyCertLoad",
- XMLSEC_ERRORS_R_NOT_IMPLEMENTED,
- XMLSEC_ERRORS_NO_MESSAGE);
- return(-1);
+ ret = xmlSecBufferInitialize(&buffer, 4*1024);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ ret = xmlSecBufferReadFile(&buffer, filename);
+ if((ret < 0) || (xmlSecBufferGetData(&buffer) == NULL) || (xmlSecBufferGetSize(&buffer) <= 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferReadFile",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "filename=%s",
+ xmlSecErrorsSafeString(filename));
+ xmlSecBufferFinalize(&buffer);
+ return(-1);
+ }
+
+ ret = xmlSecGnuTLSAppKeyCertLoadMemory(key,
+ xmlSecBufferGetData(&buffer),
+ xmlSecBufferGetSize(&buffer),
+ format);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSAppKeyCertLoadMemory",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "filename=%s",
+ xmlSecErrorsSafeString(filename));
+ xmlSecBufferFinalize(&buffer);
+ return(-1);
+ }
+
+ /* cleanup */
+ xmlSecBufferFinalize(&buffer);
+ return(0);
}
/**
@@ -192,18 +255,54 @@ xmlSecGnuTLSAppKeyCertLoadMemory(xmlSecKeyPtr key,
*/
xmlSecKeyPtr
xmlSecGnuTLSAppPkcs12Load(const char *filename,
- const char *pwd ATTRIBUTE_UNUSED,
- void* pwdCallback ATTRIBUTE_UNUSED,
- void* pwdCallbackCtx ATTRIBUTE_UNUSED) {
+ const char *pwd,
+ void* pwdCallback,
+ void* pwdCallbackCtx) {
+ xmlSecKeyPtr key;
+ xmlSecBuffer buffer;
+ int ret;
+
xmlSecAssert2(filename != NULL, NULL);
- /* TODO */
- xmlSecError(XMLSEC_ERRORS_HERE,
- NULL,
- "xmlSecGnuTLSAppPkcs12Load",
- XMLSEC_ERRORS_R_NOT_IMPLEMENTED,
- XMLSEC_ERRORS_NO_MESSAGE);
- return(NULL);
+ ret = xmlSecBufferInitialize(&buffer, 4*1024);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ ret = xmlSecBufferReadFile(&buffer, filename);
+ if((ret < 0) || (xmlSecBufferGetData(&buffer) == NULL) || (xmlSecBufferGetSize(&buffer) <= 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferReadFile",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "filename=%s",
+ xmlSecErrorsSafeString(filename));
+ xmlSecBufferFinalize(&buffer);
+ return(NULL);
+ }
+
+ key = xmlSecGnuTLSAppPkcs12LoadMemory(xmlSecBufferGetData(&buffer),
+ xmlSecBufferGetSize(&buffer),
+ pwd, pwdCallback, pwdCallbackCtx);
+ if(key == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSAppPkcs12LoadMemory",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "filename=%s",
+ xmlSecErrorsSafeString(filename));
+ xmlSecBufferFinalize(&buffer);
+ return(NULL);
+ }
+
+ /* cleanup */
+ xmlSecBufferFinalize(&buffer);
+ return(key);
}
/**
@@ -251,21 +350,58 @@ xmlSecGnuTLSAppPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize,
* Returns: 0 on success or a negative value otherwise.
*/
int
-xmlSecGnuTLSAppKeysMngrCertLoad(xmlSecKeysMngrPtr mngr,
+xmlSecGnuTLSAppKeysMngrCertLoad(xmlSecKeysMngrPtr mngr,
const char *filename,
xmlSecKeyDataFormat format,
- xmlSecKeyDataType type ATTRIBUTE_UNUSED) {
+ xmlSecKeyDataType type) {
+ xmlSecBuffer buffer;
+ int ret;
+
xmlSecAssert2(mngr != NULL, -1);
xmlSecAssert2(filename != NULL, -1);
xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1);
- /* TODO */
- xmlSecError(XMLSEC_ERRORS_HERE,
- NULL,
- "xmlSecGnuTLSAppKeysMngrCertLoad",
- XMLSEC_ERRORS_R_NOT_IMPLEMENTED,
- XMLSEC_ERRORS_NO_MESSAGE);
- return(-1);
+ ret = xmlSecBufferInitialize(&buffer, 4*1024);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ ret = xmlSecBufferReadFile(&buffer, filename);
+ if((ret < 0) || (xmlSecBufferGetData(&buffer) == NULL) || (xmlSecBufferGetSize(&buffer) <= 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferReadFile",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "filename=%s",
+ xmlSecErrorsSafeString(filename));
+ xmlSecBufferFinalize(&buffer);
+ return(-1);
+ }
+
+ ret = xmlSecGnuTLSAppKeysMngrCertLoadMemory(mngr,
+ xmlSecBufferGetData(&buffer),
+ xmlSecBufferGetSize(&buffer),
+ format,
+ type);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSAppKeysMngrCertLoadMemory",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "filename=%s",
+ xmlSecErrorsSafeString(filename));
+ xmlSecBufferFinalize(&buffer);
+ return(-1);
+ }
+
+ /* cleanup */
+ xmlSecBufferFinalize(&buffer);
+ return(0);
}
/**
diff --git a/src/gnutls/crypto.c b/src/gnutls/crypto.c
index 15f349d..83175e6 100644
--- a/src/gnutls/crypto.c
+++ b/src/gnutls/crypto.c
@@ -21,6 +21,7 @@
#include <xmlsec/gnutls/app.h>
#include <xmlsec/gnutls/crypto.h>
+#include <xmlsec/gnutls/x509.h>
static xmlSecCryptoDLFunctionsPtr gXmlSecGnuTLSFunctions = NULL;
@@ -76,11 +77,19 @@ xmlSecCryptoGetFunctions_gnutls(void) {
gXmlSecGnuTLSFunctions->keyDataRsaGetKlass = xmlSecGnuTLSKeyDataRsaGetKlass;
#endif /* XMLSEC_NO_RSA */
+#ifndef XMLSEC_NO_X509
+ gXmlSecGnuTLSFunctions->keyDataX509GetKlass = xmlSecGnuTLSKeyDataX509GetKlass;
+ gXmlSecGnuTLSFunctions->keyDataRawX509CertGetKlass = xmlSecGnuTLSKeyDataRawX509CertGetKlass;
+#endif /* XMLSEC_NO_X509 */
+
/********************************************************************
*
* Key data store ids
*
********************************************************************/
+#ifndef XMLSEC_NO_X509
+ gXmlSecGnuTLSFunctions->x509StoreGetKlass = xmlSecGnuTLSX509StoreGetKlass;
+#endif /* XMLSEC_NO_X509 */
/********************************************************************
*
@@ -276,9 +285,37 @@ xmlSecGnuTLSShutdown(void) {
*/
int
xmlSecGnuTLSKeysMngrInit(xmlSecKeysMngrPtr mngr) {
+ int ret;
+
xmlSecAssert2(mngr != NULL, -1);
- /* TODO: add key data stores */
+#ifndef XMLSEC_NO_X509
+ /* create x509 store if needed */
+ if(xmlSecKeysMngrGetDataStore(mngr, xmlSecGnuTLSX509StoreId) == NULL) {
+ xmlSecKeyDataStorePtr x509Store;
+
+ x509Store = xmlSecKeyDataStoreCreate(xmlSecGnuTLSX509StoreId);
+ if(x509Store == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecKeyDataStoreCreate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "xmlSecGnuTLSX509StoreId");
+ return(-1);
+ }
+
+ ret = xmlSecKeysMngrAdoptDataStore(mngr, x509Store);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecKeysMngrAdoptDataStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecKeyDataStoreDestroy(x509Store);
+ return(-1);
+ }
+ }
+#endif /* XMLSEC_NO_X509 */
return(0);
}
diff --git a/src/gnutls/globals.h b/src/gnutls/globals.h
index 8436900..b49e240 100644
--- a/src/gnutls/globals.h
+++ b/src/gnutls/globals.h
@@ -24,5 +24,8 @@
#define XMLSEC_GNUTLS_GCRYPT_REPORT_ERROR(err) \
"error code=%d; error message='%s'", \
(int)err, xmlSecErrorsSafeString(gcry_strerror((err)))
+#define XMLSEC_GNUTLS_REPORT_ERROR(err) \
+ "error code=%d; error message='%s'", \
+ (int)err, xmlSecErrorsSafeString(gnutls_strerror((err)))
#endif /* ! __XMLSEC_GLOBALS_H__ */
diff --git a/src/gnutls/x509.c b/src/gnutls/x509.c
new file mode 100644
index 0000000..970f5f3
--- /dev/null
+++ b/src/gnutls/x509.c
@@ -0,0 +1,1644 @@
+/**
+ * XMLSec library
+ *
+ * X509 support
+ *
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2010 Aleksey Sanin <aleksey aleksey com>
+ */
+#include "globals.h"
+
+#ifndef XMLSEC_NO_X509
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+
+#include <libxml/tree.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/errors.h>
+#include <xmlsec/private.h>
+
+#include <xmlsec/gnutls/crypto.h>
+#include <xmlsec/gnutls/x509.h>
+
+#include "x509utils.h"
+
+/*************************************************************************
+ *
+ * X509 utility functions
+ *
+ ************************************************************************/
+static int xmlSecGnuTLSX509DataNodeRead (xmlSecKeyDataPtr data,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGnuTLSX509CertificateNodeRead (xmlSecKeyDataPtr data,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGnuTLSX509CertificateNodeWrite (gnutls_x509_crt_t cert,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGnuTLSX509SubjectNameNodeRead (xmlSecKeyDataPtr data,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGnuTLSX509SubjectNameNodeWrite (gnutls_x509_crt_t cert,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGnuTLSX509IssuerSerialNodeRead (xmlSecKeyDataPtr data,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGnuTLSX509IssuerSerialNodeWrite (gnutls_x509_crt_t cert,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGnuTLSX509SKINodeRead (xmlSecKeyDataPtr data,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGnuTLSX509SKINodeWrite (gnutls_x509_crt_t cert,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGnuTLSKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr data,
+ xmlSecKeyPtr key,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+
+/*************************************************************************
+ *
+ * Internal GnuTLS X509 data CTX
+ *
+ ************************************************************************/
+typedef struct _xmlSecGnuTLSX509DataCtx xmlSecGnuTLSX509DataCtx,
+ *xmlSecGnuTLSX509DataCtxPtr;
+struct _xmlSecGnuTLSX509DataCtx {
+ gnutls_x509_crt_t keyCert;
+ xmlSecPtrList certsList;
+};
+
+
+/**************************************************************************
+ *
+ * <dsig:X509Data> processing
+ *
+ *
+ * The X509Data Element (http://www.w3.org/TR/xmldsig-core/#sec-X509Data)
+ *
+ * An X509Data element within KeyInfo contains one or more identifiers of keys
+ * or X509 certificates (or certificates' identifiers or a revocation list).
+ * The content of X509Data is:
+ *
+ * 1. At least one element, from the following set of element types; any of these may appear together or more than once iff (if and only if) each instance describes or is related to the same certificate:
+ * 2.
+ * * The X509IssuerSerial element, which contains an X.509 issuer
+ * distinguished name/serial number pair that SHOULD be compliant
+ * with RFC2253 [LDAP-DN],
+ * * The X509SubjectName element, which contains an X.509 subject
+ * distinguished name that SHOULD be compliant with RFC2253 [LDAP-DN],
+ * * The X509SKI element, which contains the base64 encoded plain (i.e.
+ * non-DER-encoded) value of a X509 V.3 SubjectKeyIdentifier extension.
+ * * The X509Certificate element, which contains a base64-encoded [X509v3]
+ * certificate, and
+ * * Elements from an external namespace which accompanies/complements any
+ * of the elements above.
+ * * The X509CRL element, which contains a base64-encoded certificate
+ * revocation list (CRL) [X509v3].
+ *
+ * Any X509IssuerSerial, X509SKI, and X509SubjectName elements that appear
+ * MUST refer to the certificate or certificates containing the validation key.
+ * All such elements that refer to a particular individual certificate MUST be
+ * grouped inside a single X509Data element and if the certificate to which
+ * they refer appears, it MUST also be in that X509Data element.
+ *
+ * Any X509IssuerSerial, X509SKI, and X509SubjectName elements that relate to
+ * the same key but different certificates MUST be grouped within a single
+ * KeyInfo but MAY occur in multiple X509Data elements.
+ *
+ * All certificates appearing in an X509Data element MUST relate to the
+ * validation key by either containing it or being part of a certification
+ * chain that terminates in a certificate containing the validation key.
+ *
+ * No ordering is implied by the above constraints.
+ *
+ * Note, there is no direct provision for a PKCS#7 encoded "bag" of
+ * certificates or CRLs. However, a set of certificates and CRLs can occur
+ * within an X509Data element and multiple X509Data elements can occur in a
+ * KeyInfo. Whenever multiple certificates occur in an X509Data element, at
+ * least one such certificate must contain the public key which verifies the
+ * signature.
+ *
+ * Schema Definition
+ *
+ * <element name="X509Data" type="ds:X509DataType"/>
+ * <complexType name="X509DataType">
+ * <sequence maxOccurs="unbounded">
+ * <choice>
+ * <element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/>
+ * <element name="X509SKI" type="base64Binary"/>
+ * <element name="X509SubjectName" type="string"/>
+ * <element name="X509Certificate" type="base64Binary"/>
+ * <element name="X509CRL" type="base64Binary"/>
+ * <any namespace="##other" processContents="lax"/>
+ * </choice>
+ * </sequence>
+ * </complexType>
+ * <complexType name="X509IssuerSerialType">
+ * <sequence>
+ * <element name="X509IssuerName" type="string"/>
+ * <element name="X509SerialNumber" type="integer"/>
+ * </sequence>
+ * </complexType>
+ *
+ * DTD
+ *
+ * <!ELEMENT X509Data ((X509IssuerSerial | X509SKI | X509SubjectName |
+ * X509Certificate | X509CRL)+ %X509.ANY;)>
+ * <!ELEMENT X509IssuerSerial (X509IssuerName, X509SerialNumber) >
+ * <!ELEMENT X509IssuerName (#PCDATA) >
+ * <!ELEMENT X509SubjectName (#PCDATA) >
+ * <!ELEMENT X509SerialNumber (#PCDATA) >
+ * <!ELEMENT X509SKI (#PCDATA) >
+ * <!ELEMENT X509Certificate (#PCDATA) >
+ * <!ELEMENT X509CRL (#PCDATA) >
+ *
+ * -----------------------------------------------------------------------
+ *
+ * xmlSecGnuTLSX509DataCtx is located after xmlSecTransform
+ *
+ *************************************************************************/
+#define xmlSecGnuTLSX509DataSize \
+ (sizeof(xmlSecKeyData) + sizeof(xmlSecGnuTLSX509DataCtx))
+#define xmlSecGnuTLSX509DataGetCtx(data) \
+ ((xmlSecGnuTLSX509DataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData)))
+
+static int xmlSecGnuTLSKeyDataX509Initialize (xmlSecKeyDataPtr data);
+static int xmlSecGnuTLSKeyDataX509Duplicate (xmlSecKeyDataPtr dst,
+ xmlSecKeyDataPtr src);
+static void xmlSecGnuTLSKeyDataX509Finalize (xmlSecKeyDataPtr data);
+static int xmlSecGnuTLSKeyDataX509XmlRead (xmlSecKeyDataId id,
+ xmlSecKeyPtr key,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGnuTLSKeyDataX509XmlWrite (xmlSecKeyDataId id,
+ xmlSecKeyPtr key,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static xmlSecKeyDataType xmlSecGnuTLSKeyDataX509GetType (xmlSecKeyDataPtr data);
+static const xmlChar* xmlSecGnuTLSKeyDataX509GetIdentifier (xmlSecKeyDataPtr data);
+
+static void xmlSecGnuTLSKeyDataX509DebugDump (xmlSecKeyDataPtr data,
+ FILE* output);
+static void xmlSecGnuTLSKeyDataX509DebugXmlDump (xmlSecKeyDataPtr data,
+ FILE* output);
+
+
+
+static xmlSecKeyDataKlass xmlSecGnuTLSKeyDataX509Klass = {
+ sizeof(xmlSecKeyDataKlass),
+ xmlSecGnuTLSX509DataSize,
+
+ /* data */
+ xmlSecNameX509Data,
+ xmlSecKeyDataUsageKeyInfoNode | xmlSecKeyDataUsageRetrievalMethodNodeXml,
+ /* xmlSecKeyDataUsage usage; */
+ xmlSecHrefX509Data, /* const xmlChar* href; */
+ xmlSecNodeX509Data, /* const xmlChar* dataNodeName; */
+ xmlSecDSigNs, /* const xmlChar* dataNodeNs; */
+
+ /* constructors/destructor */
+ xmlSecGnuTLSKeyDataX509Initialize, /* xmlSecKeyDataInitializeMethod initialize; */
+ xmlSecGnuTLSKeyDataX509Duplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */
+ xmlSecGnuTLSKeyDataX509Finalize, /* xmlSecKeyDataFinalizeMethod finalize; */
+ NULL, /* xmlSecKeyDataGenerateMethod generate; */
+
+ /* get info */
+ xmlSecGnuTLSKeyDataX509GetType, /* xmlSecKeyDataGetTypeMethod getType; */
+ NULL, /* xmlSecKeyDataGetSizeMethod getSize; */
+ xmlSecGnuTLSKeyDataX509GetIdentifier, /* xmlSecKeyDataGetIdentifier getIdentifier; */
+
+ /* read/write */
+ xmlSecGnuTLSKeyDataX509XmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */
+ xmlSecGnuTLSKeyDataX509XmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */
+ NULL, /* xmlSecKeyDataBinReadMethod binRead; */
+ NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */
+
+ /* debug */
+ xmlSecGnuTLSKeyDataX509DebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */
+ xmlSecGnuTLSKeyDataX509DebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+ /* reserved for the future */
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+/**
+ * xmlSecGnuTLSKeyDataX509GetKlass:
+ *
+ * The GnuTLS X509 key data klass (http://www.w3.org/TR/xmldsig-core/#sec-X509Data).
+ *
+ * Returns: the X509 data klass.
+ */
+xmlSecKeyDataId
+xmlSecGnuTLSKeyDataX509GetKlass(void) {
+ return(&xmlSecGnuTLSKeyDataX509Klass);
+}
+
+/**
+ * xmlSecGnuTLSKeyDataX509GetKeyCert:
+ * @data: the pointer to X509 key data.
+ *
+ * Gets the certificate from which the key was extracted.
+ *
+ * Returns: the key's certificate or NULL if key data was not used for key
+ * extraction or an error occurs.
+ */
+gnutls_x509_crt_t
+xmlSecGnuTLSKeyDataX509GetKeyCert(xmlSecKeyDataPtr data) {
+ xmlSecGnuTLSX509DataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), NULL);
+
+ ctx = xmlSecGnuTLSX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, NULL);
+
+ return(ctx->keyCert);
+}
+
+/**
+ * xmlSecGnuTLSKeyDataX509AdoptKeyCert:
+ * @data: the pointer to X509 key data.
+ * @cert: the pointer to GnuTLS X509 certificate.
+ *
+ * Sets the key's certificate in @data.
+ *
+ * Returns: 0 on success or a negative value if an error occurs.
+ */
+int
+xmlSecGnuTLSKeyDataX509AdoptKeyCert(xmlSecKeyDataPtr data, gnutls_x509_crt_t cert) {
+ xmlSecGnuTLSX509DataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), -1);
+ xmlSecAssert2(cert != NULL, -1);
+
+ ctx = xmlSecGnuTLSX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ if(ctx->keyCert != NULL) {
+ gnutls_x509_crt_deinit(ctx->keyCert);
+ }
+ ctx->keyCert = cert;
+ return(0);
+}
+
+/**
+ * xmlSecGnuTLSKeyDataX509AdoptCert:
+ * @data: the pointer to X509 key data.
+ * @cert: the pointer to GnuTLS X509 certificate.
+ *
+ * Adds certificate to the X509 key data.
+ *
+ * Returns: 0 on success or a negative value if an error occurs.
+ */
+int
+xmlSecGnuTLSKeyDataX509AdoptCert(xmlSecKeyDataPtr data, gnutls_x509_crt_t cert) {
+ xmlSecGnuTLSX509DataCtxPtr ctx;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), -1);
+ xmlSecAssert2(cert != NULL, -1);
+
+ ctx = xmlSecGnuTLSX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ ret = xmlSecPtrListAdd(&(ctx->certsList), cert);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecPtrListAdd",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ return(0);
+}
+
+/**
+ * xmlSecGnuTLSKeyDataX509GetCert:
+ * @data: the pointer to X509 key data.
+ * @pos: the desired certificate position.
+ *
+ * Gets a certificate from X509 key data.
+ *
+ * Returns: the pointer to certificate or NULL if @pos is larger than the
+ * number of certificates in @data or an error occurs.
+ */
+gnutls_x509_crt_t
+xmlSecGnuTLSKeyDataX509GetCert(xmlSecKeyDataPtr data, xmlSecSize pos) {
+ xmlSecGnuTLSX509DataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), NULL);
+
+ ctx = xmlSecGnuTLSX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, NULL);
+
+ return(xmlSecPtrListGetItem(&(ctx->certsList), pos));
+}
+
+/**
+ * xmlSecGnuTLSKeyDataX509GetCertsSize:
+ * @data: the pointer to X509 key data.
+ *
+ * Gets the number of certificates in @data.
+ *
+ * Returns: te number of certificates in @data.
+ */
+xmlSecSize
+xmlSecGnuTLSKeyDataX509GetCertsSize(xmlSecKeyDataPtr data) {
+ xmlSecGnuTLSX509DataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), 0);
+
+ ctx = xmlSecGnuTLSX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, 0);
+
+ return(xmlSecPtrListGetSize(&(ctx->certsList)));
+}
+
+static int
+xmlSecGnuTLSKeyDataX509Initialize(xmlSecKeyDataPtr data) {
+ xmlSecGnuTLSX509DataCtxPtr ctx;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), -1);
+
+ ctx = xmlSecGnuTLSX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ memset(ctx, 0, sizeof(xmlSecGnuTLSX509DataCtx));
+
+ ret = xmlSecPtrListInitialize(&(ctx->certsList), xmlSecGnuTLSX509CrtListId);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecPtrListInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "certsList");
+ return(-1);
+ }
+
+ return(0);
+}
+
+static int
+xmlSecGnuTLSKeyDataX509Duplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) {
+ xmlSecGnuTLSX509DataCtxPtr ctxSrc;
+ xmlSecGnuTLSX509DataCtxPtr ctxDst;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecGnuTLSKeyDataX509Id), -1);
+ xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecGnuTLSKeyDataX509Id), -1);
+
+ ctxSrc = xmlSecGnuTLSX509DataGetCtx(src);
+ xmlSecAssert2(ctxSrc != NULL, 0);
+ ctxDst = xmlSecGnuTLSX509DataGetCtx(dst);
+ xmlSecAssert2(ctxDst != NULL, 0);
+
+ /* copy key cert if exist */
+ if(ctxDst->keyCert != NULL) {
+ gnutls_x509_crt_deinit(ctxDst->keyCert);
+ ctxDst->keyCert = NULL;
+ }
+ if(ctxSrc->keyCert != NULL) {
+ ctxDst->keyCert = xmlSecGnuTLSX509CertDup(ctxSrc->keyCert);
+ if(ctxDst->keyCert == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(src)),
+ "xmlSecGnuTLSX509CertDup",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ }
+
+ /* copy certsList if exists */
+ xmlSecPtrListEmpty(&(ctxDst->certsList));
+ ret = xmlSecPtrListCopy(&(ctxDst->certsList), &(ctxSrc->certsList));
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(src)),
+ "xmlSecPtrListCopy",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "certsList");
+ return(-1);
+ }
+
+ /* done */
+ return(0);
+}
+
+static void
+xmlSecGnuTLSKeyDataX509Finalize(xmlSecKeyDataPtr data) {
+ xmlSecGnuTLSX509DataCtxPtr ctx;
+
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id));
+
+ ctx = xmlSecGnuTLSX509DataGetCtx(data);
+ xmlSecAssert(ctx != NULL);
+
+ xmlSecPtrListFinalize(&(ctx->certsList));
+ if(ctx->keyCert != NULL) {
+ gnutls_x509_crt_deinit(ctx->keyCert);
+ }
+ memset(ctx, 0, sizeof(xmlSecGnuTLSX509DataCtx));
+}
+
+static int
+xmlSecGnuTLSKeyDataX509XmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key,
+ xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataPtr data;
+ int ret;
+
+ xmlSecAssert2(id == xmlSecGnuTLSKeyDataX509Id, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ data = xmlSecKeyEnsureData(key, id);
+ if(data == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecKeyEnsureData",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ ret = xmlSecGnuTLSX509DataNodeRead(data, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGnuTLSX509DataNodeRead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS) == 0) {
+ ret = xmlSecGnuTLSKeyDataX509VerifyAndExtractKey(data, key, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGnuTLSKeyDataX509VerifyAndExtractKey",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+static int
+xmlSecGnuTLSKeyDataX509XmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key,
+ xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataPtr data;
+ gnutls_x509_crt_t cert;
+ xmlSecSize size, pos;
+ int content;
+ int ret;
+
+ xmlSecAssert2(id == xmlSecGnuTLSKeyDataX509Id, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ content = xmlSecX509DataGetNodeContent (node, 1, keyInfoCtx);
+ if (content < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecX509DataGetNodeContent",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "content=%d", content);
+ return(-1);
+ } else if(content == 0) {
+ /* by default we are writing certificates and crls */
+ content = XMLSEC_X509DATA_DEFAULT;
+ }
+
+ /* get x509 data */
+ data = xmlSecKeyGetData(key, id);
+ if(data == NULL) {
+ /* no x509 data in the key */
+ return(0);
+ }
+
+ /* write certs */
+ size = xmlSecGnuTLSKeyDataX509GetCertsSize(data);
+ for(pos = 0; pos < size; ++pos) {
+ cert = xmlSecGnuTLSKeyDataX509GetCert(data, pos);
+ if(cert == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGnuTLSKeyDataX509GetCert",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
+
+ if((content & XMLSEC_X509DATA_CERTIFICATE_NODE) != 0) {
+ ret = xmlSecGnuTLSX509CertificateNodeWrite(cert, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGnuTLSX509CertificateNodeWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
+ }
+
+ if((content & XMLSEC_X509DATA_SUBJECTNAME_NODE) != 0) {
+ ret = xmlSecGnuTLSX509SubjectNameNodeWrite(cert, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGnuTLSX509SubjectNameNodeWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
+ }
+
+ if((content & XMLSEC_X509DATA_ISSUERSERIAL_NODE) != 0) {
+ ret = xmlSecGnuTLSX509IssuerSerialNodeWrite(cert, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGnuTLSX509IssuerSerialNodeWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
+ }
+
+ if((content & XMLSEC_X509DATA_SKI_NODE) != 0) {
+ ret = xmlSecGnuTLSX509SKINodeWrite(cert, node, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGnuTLSX509SKINodeWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return(-1);
+ }
+ }
+ }
+
+ return(0);
+}
+
+
+static xmlSecKeyDataType
+xmlSecGnuTLSKeyDataX509GetType(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), xmlSecKeyDataTypeUnknown);
+
+ /* TODO: return verified/not verified status */
+ return(xmlSecKeyDataTypeUnknown);
+}
+
+static const xmlChar*
+xmlSecGnuTLSKeyDataX509GetIdentifier(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), NULL);
+
+ /* TODO */
+ return(NULL);
+}
+
+static void
+xmlSecGnuTLSKeyDataX509DebugDump(xmlSecKeyDataPtr data, FILE* output) {
+ gnutls_x509_crt_t cert;
+ xmlSecSize size, pos;
+
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id));
+ xmlSecAssert(output != NULL);
+
+ fprintf(output, "=== X509 Data:\n");
+ cert = xmlSecGnuTLSKeyDataX509GetKeyCert(data);
+ if(cert != NULL) {
+ fprintf(output, "==== Key Certificate:\n");
+ xmlSecGnuTLSX509CertDebugDump(cert, output);
+ }
+
+ size = xmlSecGnuTLSKeyDataX509GetCertsSize(data);
+ for(pos = 0; pos < size; ++pos) {
+ cert = xmlSecGnuTLSKeyDataX509GetCert(data, pos);
+ if(cert == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSKeyDataX509GetCert",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return;
+ }
+ fprintf(output, "==== Certificate:\n");
+ xmlSecGnuTLSX509CertDebugDump(cert, output);
+ }
+
+ /* we don't print out crls */
+}
+
+static void
+xmlSecGnuTLSKeyDataX509DebugXmlDump(xmlSecKeyDataPtr data, FILE* output) {
+ gnutls_x509_crt_t cert;
+ xmlSecSize size, pos;
+
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id));
+ xmlSecAssert(output != NULL);
+
+ fprintf(output, "<X509Data>\n");
+ cert = xmlSecGnuTLSKeyDataX509GetKeyCert(data);
+ if(cert != NULL) {
+ fprintf(output, "<KeyCertificate>\n");
+ xmlSecGnuTLSX509CertDebugXmlDump(cert, output);
+ fprintf(output, "</KeyCertificate>\n");
+ }
+
+ size = xmlSecGnuTLSKeyDataX509GetCertsSize(data);
+ for(pos = 0; pos < size; ++pos) {
+ cert = xmlSecGnuTLSKeyDataX509GetCert(data, pos);
+ if(cert == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSKeyDataX509GetCert",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%d", pos);
+ return;
+ }
+ fprintf(output, "<Certificate>\n");
+ xmlSecGnuTLSX509CertDebugXmlDump(cert, output);
+ fprintf(output, "</Certificate>\n");
+ }
+
+ /* we don't print out crls */
+ fprintf(output, "</X509Data>\n");
+}
+
+static int
+xmlSecGnuTLSX509DataNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlNodePtr cur;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ for(cur = xmlSecGetNextElementNode(node->children);
+ cur != NULL;
+ cur = xmlSecGetNextElementNode(cur->next)) {
+
+ ret = 0;
+ if(xmlSecCheckNodeName(cur, xmlSecNodeX509Certificate, xmlSecDSigNs)) {
+ ret = xmlSecGnuTLSX509CertificateNodeRead(data, cur, keyInfoCtx);
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SubjectName, xmlSecDSigNs)) {
+ ret = xmlSecGnuTLSX509SubjectNameNodeRead(data, cur, keyInfoCtx);
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerSerial, xmlSecDSigNs)) {
+ ret = xmlSecGnuTLSX509IssuerSerialNodeRead(data, cur, keyInfoCtx);
+ } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SKI, xmlSecDSigNs)) {
+ ret = xmlSecGnuTLSX509SKINodeRead(data, cur, keyInfoCtx);
+ } else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CHILD) != 0) {
+ /* laxi schema validation: ignore unknown nodes */
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "read node failed");
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+static int
+xmlSecGnuTLSX509CertificateNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlChar *content;
+ gnutls_x509_crt_t cert;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), -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) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+ XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ return(0);
+ }
+
+ cert = xmlSecGnuTLSX509CertBase64DerRead(content);
+ if(cert == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSX509CertBase64DerRead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(content);
+ return(-1);
+ }
+
+ ret = xmlSecGnuTLSKeyDataX509AdoptCert(data, cert);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSKeyDataX509AdoptCert",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ gnutls_x509_crt_deinit(cert);
+ xmlFree(content);
+ return(-1);
+ }
+
+ xmlFree(content);
+ return(0);
+}
+
+static int
+xmlSecGnuTLSX509CertificateNodeWrite(gnutls_x509_crt_t cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlChar* buf;
+ xmlNodePtr cur;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ /* set base64 lines size from context */
+ buf = xmlSecGnuTLSX509CertBase64DerWrite(cert, keyInfoCtx->base64LineSize);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertBase64DerWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ cur = xmlSecAddChild(node, xmlSecNodeX509Certificate, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509Certificate));
+ xmlFree(buf);
+ return(-1);
+ }
+
+ /* todo: add \n around base64 data - from context */
+ /* todo: add errors check */
+ xmlNodeSetContent(cur, xmlSecStringCR);
+ xmlNodeSetContent(cur, buf);
+ xmlFree(buf);
+ return(0);
+}
+
+static int
+xmlSecGnuTLSX509SubjectNameNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataStorePtr x509Store;
+ xmlChar* subject;
+ gnutls_x509_crt_t cert;
+ gnutls_x509_crt_t cert2;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+ xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1);
+
+ x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecGnuTLSX509StoreId);
+ if(x509Store == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecKeysMngrGetDataStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ 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) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+ XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ return(0);
+ }
+
+ cert = xmlSecGnuTLSX509StoreFindCert(x509Store, subject, NULL, NULL, NULL, keyInfoCtx);
+ if(cert == NULL){
+
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CERT) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_NOT_FOUND,
+ "subject=%s",
+ xmlSecErrorsSafeString(subject));
+ xmlFree(subject);
+ return(-1);
+ }
+
+ xmlFree(subject);
+ return(0);
+ }
+
+ cert2 = xmlSecGnuTLSX509CertDup(cert);
+ if(cert2 == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSX509CertDup",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+
+ xmlFree(subject);
+ return(-1);
+ }
+
+ ret = xmlSecGnuTLSKeyDataX509AdoptCert(data, cert2);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSKeyDataX509AdoptCert",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ gnutls_x509_crt_deinit(cert2);
+ xmlFree(subject);
+ return(-1);
+ }
+
+ xmlFree(subject);
+ return(0);
+}
+
+static int
+xmlSecGnuTLSX509SubjectNameNodeWrite(gnutls_x509_crt_t cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) {
+ xmlChar* buf = NULL;
+ xmlNodePtr cur = NULL;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+
+ /* add node */
+ cur = xmlSecAddChild(node, xmlSecNodeX509SubjectName, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509SubjectName));
+ return(-1);
+ }
+
+ /* get subject */
+ buf = xmlSecGnuTLSX509CertGetSubjectDN(cert);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertGetSubjectDN",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* set value */
+ xmlSecNodeEncodeAndSetContent(cur, buf);
+
+ /* done */
+ xmlFree(buf);
+ return(0);
+}
+
+static int
+xmlSecGnuTLSX509IssuerSerialNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataStorePtr x509Store;
+ xmlNodePtr cur;
+ xmlChar *issuerName;
+ xmlChar *issuerSerial;
+ gnutls_x509_crt_t cert;
+ gnutls_x509_crt_t cert2;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+ xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1);
+
+ x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecGnuTLSX509StoreId);
+ if(x509Store == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecKeysMngrGetDataStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ cur = xmlSecGetNextElementNode(node->children);
+ if(cur == NULL) {
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeX509IssuerName),
+ XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+ return(-1);
+ }
+ return(0);
+ }
+
+ /* the first is required node X509IssuerName */
+ if(!xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerName, xmlSecDSigNs)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeX509IssuerName),
+ XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+ return(-1);
+ }
+ issuerName = xmlNodeGetContent(cur);
+ if(issuerName == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509IssuerName));
+ return(-1);
+ }
+ cur = xmlSecGetNextElementNode(cur->next);
+
+ /* next is required node X509SerialNumber */
+ if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeX509SerialNumber, xmlSecDSigNs)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_NODE_NOT_FOUND,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509SerialNumber));
+ xmlFree(issuerName);
+ return(-1);
+ }
+ issuerSerial = xmlNodeGetContent(cur);
+ if(issuerSerial == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeX509SerialNumber),
+ XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)));
+ xmlFree(issuerName);
+ return(-1);
+ }
+ cur = xmlSecGetNextElementNode(cur->next);
+
+ if(cur != NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(-1);
+ }
+
+ cert = xmlSecGnuTLSX509StoreFindCert(x509Store, NULL, issuerName, issuerSerial, NULL, keyInfoCtx);
+ if(cert == NULL){
+
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CERT) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_NOT_FOUND,
+ "issuerName=%s;issuerSerial=%s",
+ xmlSecErrorsSafeString(issuerName),
+ xmlSecErrorsSafeString(issuerSerial));
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(-1);
+ }
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(0);
+ }
+
+ cert2 = xmlSecGnuTLSX509CertDup(cert);
+ if(cert2 == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSX509CertDup",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(-1);
+ }
+
+ ret = xmlSecGnuTLSKeyDataX509AdoptCert(data, cert2);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSKeyDataX509AdoptCert",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ gnutls_x509_crt_deinit(cert2);
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(-1);
+ }
+
+ xmlFree(issuerSerial);
+ xmlFree(issuerName);
+ return(0);
+}
+
+static int
+xmlSecGnuTLSX509IssuerSerialNodeWrite(gnutls_x509_crt_t cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) {
+ xmlNodePtr cur;
+ xmlNodePtr issuerNameNode;
+ xmlNodePtr issuerNumberNode;
+ xmlChar* buf;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+
+ /* create xml nodes */
+ cur = xmlSecAddChild(node, xmlSecNodeX509IssuerSerial, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509IssuerSerial));
+ return(-1);
+ }
+
+ issuerNameNode = xmlSecAddChild(cur, xmlSecNodeX509IssuerName, xmlSecDSigNs);
+ if(issuerNameNode == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509IssuerName));
+ return(-1);
+ }
+
+ issuerNumberNode = xmlSecAddChild(cur, xmlSecNodeX509SerialNumber, xmlSecDSigNs);
+ if(issuerNumberNode == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509SerialNumber));
+ return(-1);
+ }
+
+ /* write data */
+ buf = xmlSecGnuTLSX509CertGetIssuerDN(cert);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertGetIssuerDN",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ xmlSecNodeEncodeAndSetContent(issuerNameNode, buf);
+ xmlFree(buf);
+
+ buf = xmlSecGnuTLSX509CertGetIssuerSerial(cert);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertGetIssuerSerial",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ xmlSecNodeEncodeAndSetContent(issuerNumberNode, buf);
+ xmlFree(buf);
+
+ return(0);
+}
+
+
+static int
+xmlSecGnuTLSX509SKINodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataStorePtr x509Store;
+ xmlChar* ski;
+ gnutls_x509_crt_t cert;
+ gnutls_x509_crt_t cert2;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+ xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1);
+
+ x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecGnuTLSX509StoreId);
+ if(x509Store == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecKeysMngrGetDataStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ 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) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(node)),
+ XMLSEC_ERRORS_R_INVALID_NODE_CONTENT,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509SKI));
+ return(-1);
+ }
+ return(0);
+ }
+
+ cert = xmlSecGnuTLSX509StoreFindCert(x509Store, NULL, NULL, NULL, ski, keyInfoCtx);
+ if(cert == NULL){
+ xmlFree(ski);
+
+ if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CERT) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_NOT_FOUND,
+ "ski=%s",
+ xmlSecErrorsSafeString(ski));
+ return(-1);
+ }
+ return(0);
+ }
+
+ cert2 = xmlSecGnuTLSX509CertDup(cert);
+ if(cert2 == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSX509CertDup",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(ski);
+ return(-1);
+ }
+
+ ret = xmlSecGnuTLSKeyDataX509AdoptCert(data, cert2);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSKeyDataX509AdoptCert",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ gnutls_x509_crt_deinit(cert2);
+ xmlFree(ski);
+ return(-1);
+ }
+
+ xmlFree(ski);
+ return(0);
+}
+
+static int
+xmlSecGnuTLSX509SKINodeWrite(gnutls_x509_crt_t cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) {
+ xmlChar *buf = NULL;
+ xmlNodePtr cur = NULL;
+
+ xmlSecAssert2(cert != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+
+ /* add node */
+ cur = xmlSecAddChild(node, xmlSecNodeX509SKI, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "new_node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeX509SKI));
+ return(-1);
+ }
+
+ /* write value */
+ buf = xmlSecGnuTLSX509CertGetSKI(cert);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertGetSKI",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ xmlSecNodeEncodeAndSetContent(cur, buf);
+ xmlFree(buf);
+
+ return(0);
+}
+
+static int
+xmlSecGnuTLSKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr data, xmlSecKeyPtr key,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecGnuTLSX509DataCtxPtr ctx;
+ xmlSecKeyDataStorePtr x509Store;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataX509Id), -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+ xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1);
+
+ ctx = xmlSecGnuTLSX509DataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecGnuTLSX509StoreId);
+ if(x509Store == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecKeysMngrGetDataStore",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ if((ctx->keyCert == NULL) && (xmlSecPtrListGetSize(&(ctx->certsList)) > 0) && (xmlSecKeyGetValue(key) == NULL)) {
+ gnutls_x509_crt_t cert;
+
+ cert = xmlSecGnuTLSX509StoreVerify(x509Store, &(ctx->certsList), keyInfoCtx);
+ if(cert != NULL) {
+ xmlSecKeyDataPtr keyValue;
+
+ ctx->keyCert = xmlSecGnuTLSX509CertDup(cert);
+ if(ctx->keyCert == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSX509CertDup",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ keyValue = xmlSecGnuTLSX509CertGetKey(ctx->keyCert);
+ if(keyValue == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGnuTLSX509CertGetKey",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ /* verify that the key matches our expectations */
+ if(xmlSecKeyReqMatchKeyValue(&(keyInfoCtx->keyReq), keyValue) != 1) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecKeyReqMatchKeyValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecKeyDataDestroy(keyValue);
+ return(-1);
+ }
+
+ ret = xmlSecKeySetValue(key, keyValue);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecKeySetValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecKeyDataDestroy(keyValue);
+ return(-1);
+ }
+
+ /* get expiration time */
+ key->notValidBefore = gnutls_x509_crt_get_activation_time(ctx->keyCert);
+ if(key->notValidBefore == (time_t)-1) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "gnutls_x509_crt_get_activation_time",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ key->notValidAfter = gnutls_x509_crt_get_expiration_time(ctx->keyCert);
+ if(key->notValidAfter == (time_t)-1) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "gnutls_x509_crt_get_expiration_time",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ } else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_INVALID_CERT) != 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_NOT_FOUND,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+/**
+ * xmlSecGnuTLSX509CertGetKey:
+ * @cert: the certificate.
+ *
+ * Extracts public key from the @cert.
+ *
+ * Returns: public key value or NULL if an error occurs.
+ */
+xmlSecKeyDataPtr
+xmlSecGnuTLSX509CertGetKey(gnutls_x509_crt_t cert) {
+ xmlSecKeyDataPtr data;
+ int alg;
+ unsigned int bits;
+ int err;
+ int ret;
+
+ xmlSecAssert2(cert != NULL, NULL);
+
+ alg = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
+ if(alg < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_pk_algorithm",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(alg));
+ return(NULL);
+ }
+
+ switch(alg) {
+ case GNUTLS_PK_RSA:
+ {
+ gnutls_datum_t m, e;
+
+ data = xmlSecKeyDataCreate(xmlSecGnuTLSKeyDataRsaId);
+ if(data == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecKeyDataCreate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "xmlSecGnuTLSKeyDataRsaId");
+ return(NULL);
+ }
+
+ err = gnutls_x509_crt_get_pk_rsa_raw(cert, &m, &e);
+ if(err != GNUTLS_E_SUCCESS) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_pk_rsa_raw",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ return(NULL);
+ }
+
+ ret = xmlSecGnuTLSKeyDataRsaAdoptPublicKey(data, &m, &e);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSKeyDataRsaAdoptPublicKey",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ gnutls_free(m.data);
+ gnutls_free(e.data);
+ return(NULL);
+ }
+ /* m and e are owned by data now */
+ }
+ break;
+
+ case GNUTLS_PK_DSA:
+ {
+ gnutls_datum_t p, q, g, y;
+
+ data = xmlSecKeyDataCreate(xmlSecGnuTLSKeyDataDsaId);
+ if(data == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecKeyDataCreate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "xmlSecGnuTLSKeyDataDsaId");
+ return(NULL);
+ }
+
+ err = gnutls_x509_crt_get_pk_dsa_raw(cert, &p, &q, &g, &y);
+ if(err != GNUTLS_E_SUCCESS) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_pk_dsa_raw",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ return(NULL);
+ }
+
+ ret = xmlSecGnuTLSKeyDataDsaAdoptPublicKey(data, &p, &q, &g, &y);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSKeyDataDsaAdoptPublicKey",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ gnutls_free(p.data);
+ gnutls_free(q.data);
+ gnutls_free(g.data);
+ gnutls_free(y.data);
+ return(NULL);
+ }
+ /* p, q, g and y are owned by data now */
+ }
+ break;
+
+ default:
+ {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_pk_algorithm",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "Unsupported algorithm %d", (int)alg);
+ return(NULL);
+ }
+ }
+
+ /* data */
+ return(data);
+}
+
+
+/**************************************************************************
+ *
+ * Raw X509 Certificate processing
+ *
+ *
+ *************************************************************************/
+static int xmlSecGnuTLSKeyDataRawX509CertBinRead (xmlSecKeyDataId id,
+ xmlSecKeyPtr key,
+ const xmlSecByte* buf,
+ xmlSecSize bufSize,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+
+static xmlSecKeyDataKlass xmlSecGnuTLSKeyDataRawX509CertKlass = {
+ 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; */
+ xmlSecGnuTLSKeyDataRawX509CertBinRead, /* xmlSecKeyDataBinReadMethod binRead; */
+ NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */
+
+ /* debug */
+ NULL, /* xmlSecKeyDataDebugDumpMethod debugDump; */
+ NULL, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+ /* reserved for the future */
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+/**
+ * xmlSecGnuTLSKeyDataRawX509CertGetKlass:
+ *
+ * The raw X509 certificates key data klass.
+ *
+ * Returns: raw X509 certificates key data klass.
+ */
+xmlSecKeyDataId
+xmlSecGnuTLSKeyDataRawX509CertGetKlass(void) {
+ return(&xmlSecGnuTLSKeyDataRawX509CertKlass);
+}
+
+static int
+xmlSecGnuTLSKeyDataRawX509CertBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key,
+ const xmlSecByte* buf, xmlSecSize bufSize,
+ xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlSecKeyDataPtr data;
+ gnutls_x509_crt_t cert;
+ int ret;
+
+ xmlSecAssert2(id == xmlSecGnuTLSKeyDataRawX509CertId, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(buf != NULL, -1);
+ xmlSecAssert2(bufSize > 0, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ cert = xmlSecGnuTLSX509CertDerRead(buf, bufSize);
+ if(cert == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertDerRead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ data = xmlSecKeyEnsureData(key, xmlSecGnuTLSKeyDataX509Id);
+ if(data == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecKeyEnsureData",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ gnutls_x509_crt_deinit(cert);
+ return(-1);
+ }
+
+ ret = xmlSecGnuTLSKeyDataX509AdoptCert(data, cert);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGnuTLSKeyDataX509AdoptCert",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ gnutls_x509_crt_deinit(cert);
+ return(-1);
+ }
+
+ ret = xmlSecGnuTLSKeyDataX509VerifyAndExtractKey(data, key, keyInfoCtx);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGnuTLSKeyDataX509VerifyAndExtractKey",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ return(0);
+}
+
+#endif /* XMLSEC_NO_X509 */
diff --git a/src/gnutls/x509utils.c b/src/gnutls/x509utils.c
new file mode 100644
index 0000000..e87e8cf
--- /dev/null
+++ b/src/gnutls/x509utils.c
@@ -0,0 +1,562 @@
+/**
+ * XMLSec library
+ *
+ * X509 support
+ *
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2010 Aleksey Sanin <aleksey aleksey com>
+ */
+#include "globals.h"
+
+#ifndef XMLSEC_NO_X509
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+
+#include <libxml/tree.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/errors.h>
+#include <xmlsec/private.h>
+
+#include <xmlsec/gnutls/crypto.h>
+#include <xmlsec/gnutls/x509.h>
+
+#include "x509utils.h"
+
+
+/**************************************************************************
+ *
+ * X509 crt list
+ *
+ *****************************************************************************/
+static xmlSecPtr xmlSecGnuTLSX509CrtListDuplicateItem (xmlSecPtr ptr);
+static void xmlSecGnuTLSX509CrtListDestroyItem (xmlSecPtr ptr);
+static void xmlSecGnuTLSX509CrtListDebugDumpItem (xmlSecPtr ptr,
+ FILE* output);
+static void xmlSecGnuTLSX509CrtListDebugXmlDumpItem (xmlSecPtr ptr,
+ FILE* output);
+
+static xmlSecPtrListKlass xmlSecGnuTLSX509CrtListKlass = {
+ BAD_CAST "gnutls-x509-crt-list",
+ xmlSecGnuTLSX509CrtListDuplicateItem, /* xmlSecPtrDuplicateItemMethod duplicateItem; */
+ xmlSecGnuTLSX509CrtListDestroyItem, /* xmlSecPtrDestroyItemMethod destroyItem; */
+ xmlSecGnuTLSX509CrtListDebugDumpItem, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */
+ xmlSecGnuTLSX509CrtListDebugXmlDumpItem, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */
+};
+
+xmlSecPtrListId
+xmlSecGnuTLSX509CrtListGetKlass(void) {
+ return(&xmlSecGnuTLSX509CrtListKlass);
+}
+
+static xmlSecPtr
+xmlSecGnuTLSX509CrtListDuplicateItem(xmlSecPtr ptr) {
+ xmlSecAssert2(ptr != NULL, NULL);
+
+ return xmlSecGnuTLSX509CertDup((gnutls_x509_crt_t)ptr);
+}
+
+static void
+xmlSecGnuTLSX509CrtListDestroyItem(xmlSecPtr ptr) {
+ xmlSecAssert(ptr != NULL);
+
+ gnutls_x509_crt_deinit((gnutls_x509_crt_t)ptr);
+}
+
+static void
+xmlSecGnuTLSX509CrtListDebugDumpItem(xmlSecPtr ptr, FILE* output) {
+ xmlSecAssert(ptr != NULL);
+ xmlSecAssert(output != NULL);
+
+ xmlSecGnuTLSX509CertDebugDump((gnutls_x509_crt_t)ptr, output);
+}
+
+
+static void
+xmlSecGnuTLSX509CrtListDebugXmlDumpItem(xmlSecPtr ptr, FILE* output) {
+ xmlSecAssert(ptr != NULL);
+ xmlSecAssert(output != NULL);
+
+ xmlSecGnuTLSX509CertDebugXmlDump((gnutls_x509_crt_t)ptr, output);
+}
+
+/*************************************************************************
+ *
+ * Utils/helpers
+ *
+ ************************************************************************/
+
+/* HACK: gnutls doesn't have cert duplicate function, so we simply
+ write cert out and then read it back */
+gnutls_x509_crt_t
+xmlSecGnuTLSX509CertDup(gnutls_x509_crt_t src) {
+ xmlChar * buf = NULL;
+ gnutls_x509_crt_t res = NULL;
+
+ xmlSecAssert2(src != NULL, NULL);
+
+ buf = xmlSecGnuTLSX509CertBase64DerWrite(src, 0);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertBase64DerWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return (NULL);
+ }
+
+ res = xmlSecGnuTLSX509CertBase64DerRead(buf);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertBase64DerRead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(buf);
+ return (NULL);
+ }
+
+ /* done */
+ xmlFree(buf);
+ return (res);
+}
+
+xmlChar *
+xmlSecGnuTLSX509CertGetSubjectDN(gnutls_x509_crt_t cert) {
+ char* buf = NULL;
+ size_t bufSize = 0;
+ int err;
+
+ xmlSecAssert2(cert != NULL, NULL);
+
+ /* get subject size */
+ err = gnutls_x509_crt_get_dn(cert, NULL, &bufSize);
+ if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_dn",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ return(NULL);
+ }
+
+ /* allocate buffer */
+ buf = (char *)xmlMalloc(bufSize + 1);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlMalloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)bufSize);
+ return(NULL);
+ }
+
+ /* finally write it out */
+ err = gnutls_x509_crt_get_dn(cert, buf, &bufSize);
+ if(err != GNUTLS_E_SUCCESS) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_dn",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ xmlFree(buf);
+ return(NULL);
+ }
+
+ /* done */
+ return(BAD_CAST buf);
+}
+
+xmlChar *
+xmlSecGnuTLSX509CertGetIssuerDN(gnutls_x509_crt_t cert) {
+ char* buf = NULL;
+ size_t bufSize = 0;
+ int err;
+
+ xmlSecAssert2(cert != NULL, NULL);
+
+ /* get issuer size */
+ err = gnutls_x509_crt_get_issuer_dn(cert, NULL, &bufSize);
+ if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_issuer_dn",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ return(NULL);
+ }
+
+ /* allocate buffer */
+ buf = (char *)xmlMalloc(bufSize + 1);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlMalloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)bufSize);
+ return(NULL);
+ }
+
+ /* finally write it out */
+ err = gnutls_x509_crt_get_issuer_dn(cert, buf, &bufSize);
+ if(err != GNUTLS_E_SUCCESS) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_issuer_dn",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ xmlFree(buf);
+ return(NULL);
+ }
+
+ /* done */
+ return(BAD_CAST buf);
+}
+
+xmlChar *
+xmlSecGnuTLSX509CertGetIssuerSerial(gnutls_x509_crt_t cert) {
+ xmlChar * res = NULL;
+ unsigned char* buf = NULL;
+ size_t bufSize = 0;
+ int err;
+
+ xmlSecAssert2(cert != NULL, NULL);
+
+ /* get issuer serial size */
+ err = gnutls_x509_crt_get_serial(cert, NULL, &bufSize);
+ if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_serial",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ return(NULL);
+ }
+
+ /* allocate buffer */
+ buf = (unsigned char *)xmlMalloc(bufSize + 1);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlMalloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)bufSize);
+ return(NULL);
+ }
+
+ /* write it out */
+ err = gnutls_x509_crt_get_serial(cert, buf, &bufSize);
+ if(err != GNUTLS_E_SUCCESS) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_serial",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ xmlFree(buf);
+ return(NULL);
+ }
+
+ /* convert to string */
+ res = xmlSecGnuTLSASN1IntegerWrite(buf, bufSize);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSASN1IntegerWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(buf);
+ return(NULL);
+ }
+ printf("DEBUG: serial number is %s\n", res);
+
+ /* done */
+ xmlFree(buf);
+ return(res);
+}
+
+xmlChar *
+xmlSecGnuTLSX509CertGetSKI(gnutls_x509_crt_t cert) {
+ xmlChar * res = NULL;
+ xmlSecByte* buf = NULL;
+ size_t bufSize = 0;
+ unsigned int critical = 0;
+ int err;
+
+ xmlSecAssert2(cert != NULL, NULL);
+
+ /* get ski size */
+ err = gnutls_x509_crt_get_subject_key_id(cert, NULL, &bufSize, &critical);
+ if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_subject_key_id",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ return(NULL);
+ }
+
+ /* allocate buffer */
+ buf = (xmlSecByte *)xmlMalloc(bufSize + 1);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlMalloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)bufSize);
+ return(NULL);
+ }
+
+ /* write it out */
+ err = gnutls_x509_crt_get_subject_key_id(cert, buf, &bufSize, &critical);
+ if(err != GNUTLS_E_SUCCESS) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_get_subject_key_id",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ xmlFree(buf);
+ return(NULL);
+ }
+
+ /* convert to string */
+ res = xmlSecBase64Encode(buf, bufSize, 0);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64Encode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(buf);
+ return(NULL);
+ }
+
+ /* done */
+ xmlFree(buf);
+ return(res);
+}
+
+
+gnutls_x509_crt_t
+xmlSecGnuTLSX509CertBase64DerRead(xmlChar* buf) {
+ int ret;
+
+ xmlSecAssert2(buf != NULL, NULL);
+
+ /* usual trick with base64 decoding "in-place" */
+ ret = xmlSecBase64Decode(buf, (xmlSecByte*)buf, xmlStrlen(buf));
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64Decode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ return(xmlSecGnuTLSX509CertDerRead((const xmlSecByte*)buf, ret));
+}
+
+gnutls_x509_crt_t
+xmlSecGnuTLSX509CertDerRead(const xmlSecByte* buf, xmlSecSize size) {
+ gnutls_x509_crt_t cert = NULL;
+ gnutls_datum_t data;
+ int err;
+
+ xmlSecAssert2(buf != NULL, NULL);
+ xmlSecAssert2(size > 0, NULL);
+
+ err = gnutls_x509_crt_init(&cert);
+ if(err != GNUTLS_E_SUCCESS) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_init",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ return(NULL);
+ }
+
+ data.data = (unsigned char*)buf;
+ data.size = size;
+ err = gnutls_x509_crt_import(cert, &data, GNUTLS_X509_FMT_DER);
+ if(err != GNUTLS_E_SUCCESS) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_import",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ gnutls_x509_crt_deinit(cert);
+ return(NULL);
+ }
+
+ return(cert);
+}
+
+xmlChar*
+xmlSecGnuTLSX509CertBase64DerWrite(gnutls_x509_crt_t cert, int base64LineWrap) {
+ xmlChar * res = NULL;
+ xmlSecByte* buf = NULL;
+ size_t bufSize = 0;
+ int err;
+
+ xmlSecAssert2(cert != NULL, NULL);
+
+ /* get size */
+ err = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, NULL, &bufSize);
+ if((err != GNUTLS_E_SHORT_MEMORY_BUFFER) || (bufSize <= 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_export(GNUTLS_X509_FMT_DER)",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ return(NULL);
+ }
+
+ /* allocate buffer */
+ buf = (xmlSecByte *)xmlMalloc(bufSize + 1);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlMalloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)bufSize);
+ return(NULL);
+ }
+
+ /* write it out */
+ err = gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, buf, &bufSize);
+ if(err != GNUTLS_E_SUCCESS) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gnutls_x509_crt_export(GNUTLS_X509_FMT_DER)",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GNUTLS_REPORT_ERROR(err));
+ xmlFree(buf);
+ return(NULL);
+ }
+
+ /* convert to string */
+ res = xmlSecBase64Encode(buf, bufSize, base64LineWrap);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBase64Encode",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlFree(buf);
+ return(NULL);
+ }
+
+ /* done */
+ xmlFree(buf);
+ return(res);
+}
+
+void
+xmlSecGnuTLSX509CertDebugDump(gnutls_x509_crt_t cert, FILE* output) {
+ xmlChar * buf;
+
+ xmlSecAssert(cert != NULL);
+ xmlSecAssert(output != NULL);
+
+ buf = xmlSecGnuTLSX509CertGetSubjectDN(cert);
+ if(buf != NULL) {
+ fprintf(output, "==== Subject Name: %s\n", buf);
+ xmlFree(buf);
+ } else {
+ fprintf(output, "==== Subject Name: unknown\n");
+ }
+
+ buf = xmlSecGnuTLSX509CertGetIssuerDN(cert);
+ if(buf != NULL) {
+ fprintf(output, "==== Issuer Name: %s\n", buf);
+ xmlFree(buf);
+ } else {
+ fprintf(output, "==== Issuer Name: unknown\n");
+ }
+
+ buf = xmlSecGnuTLSX509CertGetIssuerSerial(cert);
+ if(buf != NULL) {
+ fprintf(output, "==== Issuer Serial: %s\n", buf);
+ xmlFree(buf);
+ } else {
+ fprintf(output, "==== Issuer Serial: unknown\n");
+ }
+}
+
+void
+xmlSecGnuTLSX509CertDebugXmlDump(gnutls_x509_crt_t cert, FILE* output) {
+ xmlChar * buf;
+
+ xmlSecAssert(cert != NULL);
+ xmlSecAssert(output != NULL);
+
+ buf = xmlSecGnuTLSX509CertGetSubjectDN(cert);
+ if(buf != NULL) {
+ fprintf(output, "<SubjectName>%s</SubjectName>\n", buf);
+ xmlFree(buf);
+ } else {
+ fprintf(output, "<SubjectName>unknown</SubjectName>\n");
+ }
+
+ buf = xmlSecGnuTLSX509CertGetIssuerDN(cert);
+ if(buf != NULL) {
+ fprintf(output, "<IssuerName>%s</IssuerName>\n", buf);
+ xmlFree(buf);
+ } else {
+ fprintf(output, "<IssuerName>unknown</IssuerName>\n");
+ }
+
+ buf = xmlSecGnuTLSX509CertGetIssuerSerial(cert);
+ if(buf != NULL) {
+ fprintf(output, "<SerialNumber>%s</SerialNumber>\n", buf);
+ xmlFree(buf);
+ } else {
+ fprintf(output, "<SerialNumber>unknown</SerialNumber>\n");
+ }
+}
+
+xmlChar*
+xmlSecGnuTLSASN1IntegerWrite(const unsigned char * data, size_t len) {
+ xmlChar *res = NULL;
+ int resLen = 64; /* not more than 64 chars */
+ unsigned long long int val = 0;
+ size_t ii = 0;
+ int shift = 0;
+
+ xmlSecAssert2(data != NULL, NULL);
+ xmlSecAssert2(len <= 8, NULL);
+
+ /* HACK : to be fixed after GnuTLS provides a way to read opaque ASN1 integer */
+ for(ii = len; ii > 0; --ii, shift += 8) {
+ val |= ((unsigned long long)data[ii - 1]) << shift;
+ }
+
+ res = (xmlChar*)xmlMalloc(resLen + 1);
+ if(res == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlMalloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)resLen);
+ return (NULL);
+ }
+
+ xmlSecStrPrintf(res, resLen, BAD_CAST "%llu", val);
+ return(res);
+}
+
+#endif /* XMLSEC_NO_X509 */
diff --git a/src/gnutls/x509utils.h b/src/gnutls/x509utils.h
new file mode 100644
index 0000000..b0727f2
--- /dev/null
+++ b/src/gnutls/x509utils.h
@@ -0,0 +1,65 @@
+/*
+ * XML Security Library
+ *
+ * THIS IS A PRIVATE XMLSEC HEADER FILE
+ * DON'T USE IT IN YOUR APPLICATION
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2010 Aleksey Sanin <aleksey aleksey com>
+ */
+#ifndef __XMLSEC_GNUTLS_X509UTILS_H__
+#define __XMLSEC_GNUTLS_X509UTILS_H__
+
+#ifndef XMLSEC_PRIVATE
+#error "gnutls/x509utils.h file contains private xmlsec definitions and should not be used outside xmlsec or xmlsec-<crypto> libraries"
+#endif /* XMLSEC_PRIVATE */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef XMLSEC_NO_X509
+
+/**************************************************************************
+ *
+ * X509 certs list
+ *
+ *****************************************************************************/
+#define xmlSecGnuTLSX509CrtListId \
+ xmlSecGnuTLSX509CrtListGetKlass()
+xmlSecPtrListId xmlSecGnuTLSX509CrtListGetKlass (void);
+
+
+/*************************************************************************
+ *
+ * Utils/helpers
+ *
+ ************************************************************************/
+gnutls_x509_crt_t xmlSecGnuTLSX509CertDup (gnutls_x509_crt_t src);
+xmlChar * xmlSecGnuTLSX509CertGetSubjectDN (gnutls_x509_crt_t cert);
+xmlChar * xmlSecGnuTLSX509CertGetIssuerDN (gnutls_x509_crt_t cert);
+xmlChar * xmlSecGnuTLSX509CertGetIssuerSerial (gnutls_x509_crt_t cert);
+xmlChar * xmlSecGnuTLSX509CertGetSKI (gnutls_x509_crt_t cert);
+gnutls_x509_crt_t xmlSecGnuTLSX509CertDerRead (const xmlSecByte* buf,
+ xmlSecSize size);
+gnutls_x509_crt_t xmlSecGnuTLSX509CertBase64DerRead (xmlChar* buf);
+xmlChar* xmlSecGnuTLSX509CertBase64DerWrite (gnutls_x509_crt_t cert,
+ int base64LineWrap);
+void xmlSecGnuTLSX509CertDebugDump (gnutls_x509_crt_t cert,
+ FILE* output);
+void xmlSecGnuTLSX509CertDebugXmlDump (gnutls_x509_crt_t cert,
+ FILE* output);
+xmlChar* xmlSecGnuTLSASN1IntegerWrite (const unsigned char * data,
+ size_t len);
+
+
+#endif /* XMLSEC_NO_X509 */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* ! __XMLSEC_GNUTLS_X509UTILS_H__ */
diff --git a/src/gnutls/x509vfy.c b/src/gnutls/x509vfy.c
new file mode 100644
index 0000000..e4bb7d1
--- /dev/null
+++ b/src/gnutls/x509vfy.c
@@ -0,0 +1,541 @@
+/**
+ * XMLSec library
+ *
+ * X509 support
+ *
+ *
+ * This is free software; see Copyright file in the source
+ * distribution for preciese wording.
+ *
+ * Copyright (C) 2010 Aleksey Sanin <aleksey aleksey com>
+ */
+#include "globals.h"
+
+#ifndef XMLSEC_NO_X509
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <libxml/tree.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/keyinfo.h>
+#include <xmlsec/keysmngr.h>
+#include <xmlsec/base64.h>
+#include <xmlsec/errors.h>
+
+#include <xmlsec/gnutls/crypto.h>
+#include <xmlsec/gnutls/x509.h>
+
+#include "x509utils.h"
+
+/**************************************************************************
+ *
+ * Internal GnuTLS X509 store CTX
+ *
+ *************************************************************************/
+typedef struct _xmlSecGnuTLSX509StoreCtx xmlSecGnuTLSX509StoreCtx,
+ *xmlSecGnuTLSX509StoreCtxPtr;
+struct _xmlSecGnuTLSX509StoreCtx {
+ xmlSecPtrList certsTrusted;
+ xmlSecPtrList certsUntrusted;
+};
+
+/****************************************************************************
+ *
+ * xmlSecGnuTLSKeyDataStoreX509Id:
+ *
+ * xmlSecGnuTLSX509StoreCtx is located after xmlSecTransform
+ *
+ ***************************************************************************/
+#define xmlSecGnuTLSX509StoreGetCtx(store) \
+ ((xmlSecGnuTLSX509StoreCtxPtr)(((xmlSecByte*)(store)) + \
+ sizeof(xmlSecKeyDataStoreKlass)))
+#define xmlSecGnuTLSX509StoreSize \
+ (sizeof(xmlSecKeyDataStoreKlass) + sizeof(xmlSecGnuTLSX509StoreCtx))
+
+static int xmlSecGnuTLSX509StoreInitialize (xmlSecKeyDataStorePtr store);
+static void xmlSecGnuTLSX509StoreFinalize (xmlSecKeyDataStorePtr store);
+
+static xmlSecKeyDataStoreKlass xmlSecGnuTLSX509StoreKlass = {
+ sizeof(xmlSecKeyDataStoreKlass),
+ xmlSecGnuTLSX509StoreSize,
+
+ /* data */
+ xmlSecNameX509Store, /* const xmlChar* name; */
+
+ /* constructors/destructor */
+ xmlSecGnuTLSX509StoreInitialize, /* xmlSecKeyDataStoreInitializeMethod initialize; */
+ xmlSecGnuTLSX509StoreFinalize, /* xmlSecKeyDataStoreFinalizeMethod finalize; */
+
+ /* reserved for the future */
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+static gnutls_x509_crt_t xmlSecGnuTLSX509FindCert (xmlSecPtrListPtr certs,
+ const xmlChar *subjectName,
+ const xmlChar *issuerName,
+ const xmlChar *issuerSerial,
+ const xmlChar *ski);
+
+/**
+ * xmlSecGnuTLSX509StoreGetKlass:
+ *
+ * The GnuTLS X509 certificates key data store klass.
+ *
+ * Returns: pointer to GnuTLS X509 certificates key data store klass.
+ */
+xmlSecKeyDataStoreId
+xmlSecGnuTLSX509StoreGetKlass(void) {
+ return(&xmlSecGnuTLSX509StoreKlass);
+}
+
+/**
+ * xmlSecGnuTLSX509StoreFindCert:
+ * @store: the pointer to X509 key data store klass.
+ * @subjectName: the desired certificate name.
+ * @issuerName: the desired certificate issuer name.
+ * @issuerSerial: the desired certificate issuer serial number.
+ * @ski: the desired certificate SKI.
+ * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Searches @store for a certificate that matches given criteria.
+ *
+ * Returns: pointer to found certificate or NULL if certificate is not found
+ * or an error occurs.
+ */
+gnutls_x509_crt_t
+xmlSecGnuTLSX509StoreFindCert(xmlSecKeyDataStorePtr store,
+ const xmlChar *subjectName,
+ const xmlChar *issuerName,
+ const xmlChar *issuerSerial,
+ const xmlChar *ski,
+ const xmlSecKeyInfoCtx* keyInfoCtx) {
+ xmlSecGnuTLSX509StoreCtxPtr ctx;
+ gnutls_x509_crt_t res = NULL;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), NULL);
+ xmlSecAssert2(keyInfoCtx != NULL, NULL);
+
+ ctx = xmlSecGnuTLSX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, NULL);
+
+ if(res == NULL) {
+ res = xmlSecGnuTLSX509FindCert(&(ctx->certsTrusted), subjectName, issuerName, issuerSerial, ski);
+ }
+ if(res == NULL) {
+ res = xmlSecGnuTLSX509FindCert(&(ctx->certsUntrusted), subjectName, issuerName, issuerSerial, ski);
+ }
+ return(res);
+}
+
+/**
+ * xmlSecGnuTLSX509StoreVerify:
+ * @store: the pointer to X509 key data store klass.
+ * @certs: the untrusted certificates stack.
+ * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context.
+ *
+ * Verifies @certs list.
+ *
+ * Returns: pointer to the first verified certificate from @certs.
+ */
+gnutls_x509_crt_t
+xmlSecGnuTLSX509StoreVerify(xmlSecKeyDataStorePtr store,
+ xmlSecPtrListPtr certs,
+ const xmlSecKeyInfoCtx* keyInfoCtx) {
+ return(NULL);
+
+#ifdef TODO
+ xmlSecGnuTLSX509StoreCtxPtr ctx;
+ STACK_OF(X509)* certs2 = NULL;
+ X509 * res = NULL;
+ X509 * cert;
+ X509 * err_cert = NULL;
+ char buf[256];
+ int err = 0, depth;
+ int i;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), NULL);
+ xmlSecAssert2(certs != NULL, NULL);
+ xmlSecAssert2(keyInfoCtx != NULL, NULL);
+
+ ctx = xmlSecGnuTLSX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, NULL);
+ xmlSecAssert2(ctx->xst != NULL, NULL);
+
+ /* dup certs */
+ certs2 = sk_X509_dup(certs);
+ if(certs2 == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "sk_X509_dup",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+ /* add untrusted certs from the store */
+ for(i = 0; i < sk_X509_num(ctx->certsUntrusted); ++i) {
+ ret = sk_X509_push(certs2, sk_X509_value(ctx->certsUntrusted, i));
+ if(ret < 1) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "sk_X509_push",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ }
+
+ /* TODO: remove all revoked certs */
+
+ /* get one cert after another and try to verify */
+ for(i = 0; i < sk_X509_num(certs2); ++i) {
+ cert = sk_X509_value(certs2, i);
+ if(xmlSecGnuTLSX509FindNextChainCert(certs2, cert) == NULL) {
+ X509_STORE_CTX xsc;
+
+#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097)
+ X509_VERIFY_PARAM * vpm = NULL;
+ unsigned long vpm_flags = 0;
+
+ vpm = X509_VERIFY_PARAM_new();
+ if(vpm == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "X509_VERIFY_PARAM_new",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ vpm_flags = vpm->flags;
+/*
+ vpm_flags &= (~X509_V_FLAG_X509_STRICT);
+*/
+
+ X509_VERIFY_PARAM_set_depth(vpm, 9);
+ X509_VERIFY_PARAM_set_flags(vpm, vpm_flags);
+#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */
+
+
+ X509_STORE_CTX_init (&xsc, ctx->xst, cert, certs2);
+
+ if(keyInfoCtx->certsVerificationTime > 0) {
+#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097)
+ vpm_flags |= X509_V_FLAG_USE_CHECK_TIME;
+ X509_VERIFY_PARAM_set_time(vpm, keyInfoCtx->certsVerificationTime);
+#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */
+ X509_STORE_CTX_set_time(&xsc, 0, keyInfoCtx->certsVerificationTime);
+ }
+
+#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097)
+ X509_STORE_CTX_set0_param(&xsc, vpm);
+#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */
+
+
+ ret = X509_verify_cert(&xsc);
+ err_cert = X509_STORE_CTX_get_current_cert(&xsc);
+ err = X509_STORE_CTX_get_error(&xsc);
+ depth = X509_STORE_CTX_get_error_depth(&xsc);
+
+ X509_STORE_CTX_cleanup (&xsc);
+
+ if(ret == 1) {
+ res = cert;
+ goto done;
+ } else if(ret < 0) {
+ const char* err_msg;
+
+ buf[0] = '\0';
+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof buf);
+ err_msg = X509_verify_cert_error_string(err);
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "X509_verify_cert",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "subj=%s;err=%d;msg=%s",
+ xmlSecErrorsSafeString(buf),
+ err,
+ xmlSecErrorsSafeString(err_msg));
+ goto done;
+ } else if(ret == 0) {
+ const char* err_msg;
+
+ buf[0] = '\0';
+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof buf);
+ err_msg = X509_verify_cert_error_string(err);
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "X509_verify_cert",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "subj=%s;err=%d;msg=%s",
+ xmlSecErrorsSafeString(buf),
+ err,
+ xmlSecErrorsSafeString(err_msg));
+ }
+ }
+ }
+
+ /* if we came here then we found nothing. do we have any error? */
+ if((err != 0) && (err_cert != NULL)) {
+ const char* err_msg;
+
+ err_msg = X509_verify_cert_error_string(err);
+ switch (err) {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, sizeof buf);
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_ISSUER_FAILED,
+ "err=%d;msg=%s;issuer=%s",
+ err,
+ xmlSecErrorsSafeString(err_msg),
+ xmlSecErrorsSafeString(buf));
+ break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_NOT_YET_VALID,
+ "err=%d;msg=%s", err,
+ xmlSecErrorsSafeString(err_msg));
+ break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_HAS_EXPIRED,
+ "err=%d;msg=%s", err,
+ xmlSecErrorsSafeString(err_msg));
+ break;
+ default:
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ NULL,
+ XMLSEC_ERRORS_R_CERT_VERIFY_FAILED,
+ "err=%d;msg=%s", err,
+ xmlSecErrorsSafeString(err_msg));
+ }
+ }
+
+done:
+ if(certs2 != NULL) {
+ sk_X509_free(certs2);
+ }
+ return(res);
+#endif /* TODO */
+}
+
+/**
+ * xmlSecGnuTLSX509StoreAdoptCert:
+ * @store: the pointer to X509 key data store klass.
+ * @cert: the pointer to GnuTLS X509 certificate.
+ * @type: the certificate type (trusted/untrusted).
+ *
+ * Adds trusted (root) or untrusted certificate to the store.
+ *
+ * Returns: 0 on success or a negative value if an error occurs.
+ */
+int
+xmlSecGnuTLSX509StoreAdoptCert(xmlSecKeyDataStorePtr store, gnutls_x509_crt_t cert, xmlSecKeyDataType type) {
+ xmlSecGnuTLSX509StoreCtxPtr ctx;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), -1);
+ xmlSecAssert2(cert != NULL, -1);
+
+ ctx = xmlSecGnuTLSX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ if((type & xmlSecKeyDataTypeTrusted) != 0) {
+ ret = xmlSecPtrListAdd(&(ctx->certsTrusted), cert);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "xmlSecPtrListAdd(trusted)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ } else {
+ ret = xmlSecPtrListAdd(&(ctx->certsUntrusted), cert);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "xmlSecPtrListAdd(untrusted)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ }
+
+ /* done */
+ return(0);
+}
+
+static int
+xmlSecGnuTLSX509StoreInitialize(xmlSecKeyDataStorePtr store) {
+ xmlSecGnuTLSX509StoreCtxPtr ctx;
+ int ret;
+
+ xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId), -1);
+
+ ctx = xmlSecGnuTLSX509StoreGetCtx(store);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ memset(ctx, 0, sizeof(xmlSecGnuTLSX509StoreCtx));
+
+ ret = xmlSecPtrListInitialize(&(ctx->certsTrusted), xmlSecGnuTLSX509CrtListId);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "xmlSecPtrListInitialize(trusted)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ ret = xmlSecPtrListInitialize(&(ctx->certsUntrusted), xmlSecGnuTLSX509CrtListId);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)),
+ "xmlSecPtrListInitialize(untrusted)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+
+ return(0);
+}
+
+static void
+xmlSecGnuTLSX509StoreFinalize(xmlSecKeyDataStorePtr store) {
+ xmlSecGnuTLSX509StoreCtxPtr ctx;
+ xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecGnuTLSX509StoreId));
+
+ ctx = xmlSecGnuTLSX509StoreGetCtx(store);
+ xmlSecAssert(ctx != NULL);
+
+ xmlSecPtrListFinalize(&(ctx->certsTrusted));
+ xmlSecPtrListFinalize(&(ctx->certsUntrusted));
+
+ memset(ctx, 0, sizeof(xmlSecGnuTLSX509StoreCtx));
+}
+
+
+/*****************************************************************************
+ *
+ * Low-level x509 functions
+ *
+ *****************************************************************************/
+static gnutls_x509_crt_t
+xmlSecGnuTLSX509FindCert(xmlSecPtrListPtr certs,
+ const xmlChar *subjectName,
+ const xmlChar *issuerName,
+ const xmlChar *issuerSerial,
+ const xmlChar *ski) {
+ xmlSecSize ii, sz;
+
+ xmlSecAssert2(certs != NULL, NULL);
+
+
+ /* todo: this is not the fastest way to search certs */
+ sz = xmlSecPtrListGetSize(certs);
+ for(ii = 0; (ii < sz); ++ii) {
+ gnutls_x509_crt_t cert = xmlSecPtrListGetItem(certs, ii);
+ if(cert == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecPtrListGetItem",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%i", (int)ii);
+ return(NULL);
+ }
+
+ if(subjectName != NULL) {
+ xmlChar * tmp;
+
+ tmp = xmlSecGnuTLSX509CertGetSubjectDN(cert);
+ if(tmp == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertGetSubjectDN",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%i", (int)ii);
+ return(NULL);
+ }
+
+ if(xmlStrEqual(subjectName, tmp)) {
+ xmlFree(tmp);
+ return(cert);
+ }
+ xmlFree(tmp);
+ } else if((issuerName != NULL) && (issuerSerial != NULL)) {
+ xmlChar * tmp1;
+ xmlChar * tmp2;
+
+ tmp1 = xmlSecGnuTLSX509CertGetIssuerDN(cert);
+ if(tmp1 == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertGetIssuerDN",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%i", (int)ii);
+ return(NULL);
+ }
+
+ tmp2 = xmlSecGnuTLSX509CertGetIssuerSerial(cert);
+ if(tmp2 == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertGetIssuerSerial",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%i", (int)ii);
+ xmlFree(tmp1);
+ return(NULL);
+ }
+
+ if(xmlStrEqual(issuerName, tmp1) && xmlStrEqual(issuerSerial, tmp2)) {
+ xmlFree(tmp1);
+ xmlFree(tmp2);
+ return(cert);
+ }
+ xmlFree(tmp1);
+ xmlFree(tmp2);
+ } else if(ski != NULL) {
+ xmlChar * tmp;
+
+ tmp = xmlSecGnuTLSX509CertGetSKI(cert);
+ if(tmp == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGnuTLSX509CertGetSKI",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "pos=%i", (int)ii);
+ return(NULL);
+ }
+
+ if(xmlStrEqual(ski, tmp)) {
+ xmlFree(tmp);
+ return(cert);
+ }
+ xmlFree(tmp);
+ }
+ }
+
+ return(NULL);
+}
+
+#endif /* XMLSEC_NO_X509 */
+
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]