summaryrefslogtreecommitdiff
path: root/src/gcrypt/asymkeys.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gcrypt/asymkeys.c')
-rw-r--r--src/gcrypt/asymkeys.c1920
1 files changed, 1920 insertions, 0 deletions
diff --git a/src/gcrypt/asymkeys.c b/src/gcrypt/asymkeys.c
new file mode 100644
index 00000000..8f0cec88
--- /dev/null
+++ b/src/gcrypt/asymkeys.c
@@ -0,0 +1,1920 @@
+/**
+ * XMLSec library
+ *
+ * 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"
+
+#include <string.h>
+
+#include <gcrypt.h>
+
+#include <xmlsec/xmlsec.h>
+#include <xmlsec/xmltree.h>
+#include <xmlsec/keys.h>
+#include <xmlsec/base64.h>
+#include <xmlsec/keyinfo.h>
+#include <xmlsec/transforms.h>
+#include <xmlsec/errors.h>
+
+#include <xmlsec/gcrypt/crypto.h>
+
+/**************************************************************************
+ *
+ * Helpers
+ *
+ *************************************************************************/
+static gcry_sexp_t xmlSecGCryptAsymSExpDup (gcry_sexp_t sexp);
+
+
+/**************************************************************************
+ *
+ * Internal GCrypt asym key CTX
+ *
+ *************************************************************************/
+typedef struct _xmlSecGCryptAsymKeyDataCtx xmlSecGCryptAsymKeyDataCtx,
+ *xmlSecGCryptAsymKeyDataCtxPtr;
+struct _xmlSecGCryptAsymKeyDataCtx {
+ gcry_sexp_t pub_key;
+ gcry_sexp_t priv_key;
+};
+
+/******************************************************************************
+ *
+ * Asym key (dsa/rsa)
+ *
+ * xmlSecGCryptAsymKeyDataCtx is located after xmlSecTransform
+ *
+ *****************************************************************************/
+#define xmlSecGCryptAsymKeyDataSize \
+ (sizeof(xmlSecKeyData) + sizeof(xmlSecGCryptAsymKeyDataCtx))
+#define xmlSecGCryptAsymKeyDataGetCtx(data) \
+ ((xmlSecGCryptAsymKeyDataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData)))
+
+static int xmlSecGCryptAsymKeyDataInitialize (xmlSecKeyDataPtr data);
+static int xmlSecGCryptAsymKeyDataDuplicate (xmlSecKeyDataPtr dst,
+ xmlSecKeyDataPtr src);
+static void xmlSecGCryptAsymKeyDataFinalize (xmlSecKeyDataPtr data);
+
+static int xmlSecGCryptAsymKeyDataAdoptKey (xmlSecKeyDataPtr data,
+ gcry_sexp_t key_pair);
+static int xmlSecGCryptAsymKeyDataAdoptKeyPair (xmlSecKeyDataPtr data,
+ gcry_sexp_t pub_key,
+ gcry_sexp_t priv_key);
+static gcry_sexp_t xmlSecGCryptAsymKeyDataGetPublicKey (xmlSecKeyDataPtr data);
+static gcry_sexp_t xmlSecGCryptAsymKeyDataGetPrivateKey (xmlSecKeyDataPtr data);
+static int xmlSecGCryptAsymKeyDataGenerate (xmlSecKeyDataPtr data,
+ const char * alg,
+ xmlSecSize key_size);
+static xmlSecKeyDataType xmlSecGCryptAsymKeyDataGetType (xmlSecKeyDataPtr data);
+static xmlSecSize xmlSecGCryptAsymKeyDataGetSize (xmlSecKeyDataPtr data);
+
+
+static int
+xmlSecGCryptAsymKeyDataInitialize(xmlSecKeyDataPtr data) {
+ xmlSecGCryptAsymKeyDataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataIsValid(data), -1);
+ xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecGCryptAsymKeyDataSize), -1);
+
+ ctx = xmlSecGCryptAsymKeyDataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ memset(ctx, 0, sizeof(xmlSecGCryptAsymKeyDataCtx));
+
+ return(0);
+}
+
+static int
+xmlSecGCryptAsymKeyDataDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) {
+ xmlSecGCryptAsymKeyDataCtxPtr ctxDst;
+ xmlSecGCryptAsymKeyDataCtxPtr ctxSrc;
+
+ xmlSecAssert2(xmlSecKeyDataIsValid(dst), -1);
+ xmlSecAssert2(xmlSecKeyDataCheckSize(dst, xmlSecGCryptAsymKeyDataSize), -1);
+ xmlSecAssert2(xmlSecKeyDataIsValid(src), -1);
+ xmlSecAssert2(xmlSecKeyDataCheckSize(src, xmlSecGCryptAsymKeyDataSize), -1);
+
+ ctxDst = xmlSecGCryptAsymKeyDataGetCtx(dst);
+ xmlSecAssert2(ctxDst != NULL, -1);
+ xmlSecAssert2(ctxDst->pub_key == NULL, -1);
+ xmlSecAssert2(ctxDst->priv_key == NULL, -1);
+
+ ctxSrc = xmlSecGCryptAsymKeyDataGetCtx(src);
+ xmlSecAssert2(ctxSrc != NULL, -1);
+
+ if(ctxSrc->pub_key != NULL) {
+ ctxDst->pub_key = xmlSecGCryptAsymSExpDup(ctxSrc->pub_key);
+ if(ctxDst->pub_key == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)),
+ "xmlSecGCryptAsymSExpDup(pub_key)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ }
+
+ if(ctxSrc->priv_key != NULL) {
+ ctxDst->priv_key = xmlSecGCryptAsymSExpDup(ctxSrc->priv_key);
+ if(ctxDst->priv_key == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)),
+ "xmlSecGCryptAsymSExpDup(priv_key)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(-1);
+ }
+ }
+
+ return(0);
+}
+
+static void
+xmlSecGCryptAsymKeyDataFinalize(xmlSecKeyDataPtr data) {
+ xmlSecGCryptAsymKeyDataCtxPtr ctx;
+
+ xmlSecAssert(xmlSecKeyDataIsValid(data));
+ xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecGCryptAsymKeyDataSize));
+
+ ctx = xmlSecGCryptAsymKeyDataGetCtx(data);
+ xmlSecAssert(ctx != NULL);
+
+ if(ctx->pub_key != NULL) {
+ gcry_sexp_release(ctx->pub_key);
+ }
+ if(ctx->priv_key != NULL) {
+ gcry_sexp_release(ctx->priv_key);
+ }
+ memset(ctx, 0, sizeof(xmlSecGCryptAsymKeyDataCtx));
+}
+
+static int
+xmlSecGCryptAsymKeyDataAdoptKey(xmlSecKeyDataPtr data, gcry_sexp_t key_pair) {
+ xmlSecGCryptAsymKeyDataCtxPtr ctx;
+ gcry_sexp_t pub_key = NULL;
+ gcry_sexp_t priv_key = NULL;
+ int res = -1;
+
+ xmlSecAssert2(xmlSecKeyDataIsValid(data), -1);
+ xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecGCryptAsymKeyDataSize), -1);
+ xmlSecAssert2(key_pair != NULL, -1);
+
+ ctx = xmlSecGCryptAsymKeyDataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ /* split the key pair, public part should be always present, private might
+ not be present */
+ pub_key = gcry_sexp_find_token(key_pair, "public-key", 0);
+ if(pub_key == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_sexp_find_token(public-key)",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ priv_key = gcry_sexp_find_token(key_pair, "private-key", 0);
+
+ /* assign */
+ if(xmlSecGCryptAsymKeyDataAdoptKeyPair(data, pub_key, priv_key) < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGCryptAsymKeyDataAdoptKeyPair",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ pub_key = NULL; /* data owns it now */
+ priv_key = NULL; /* data owns it now */
+
+ /* success */
+ res = 0;
+
+done:
+ if(pub_key != NULL) {
+ gcry_sexp_release(pub_key);
+ }
+
+ if(priv_key != NULL) {
+ gcry_sexp_release(priv_key);
+ }
+
+ /* done */
+ return(res);
+}
+
+static int
+xmlSecGCryptAsymKeyDataAdoptKeyPair(xmlSecKeyDataPtr data, gcry_sexp_t pub_key, gcry_sexp_t priv_key) {
+ xmlSecGCryptAsymKeyDataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataIsValid(data), -1);
+ xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecGCryptAsymKeyDataSize), -1);
+ xmlSecAssert2(pub_key != NULL, -1); /* public key should present always */
+/*
+ aleksey - we don't set optional parameters for RSA keys (p, k, u) and
+ because of that we can't actually test the key
+
+ xmlSecAssert2(((priv_key == NULL) || (gcry_pk_testkey(priv_key) == GPG_ERR_NO_ERROR)), -1);
+*/
+
+ ctx = xmlSecGCryptAsymKeyDataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ /* release prev values and assign new ones */
+ if(ctx->pub_key != NULL) {
+ gcry_sexp_release(ctx->pub_key);
+ }
+ if(ctx->priv_key != NULL) {
+ gcry_sexp_release(ctx->priv_key);
+ }
+
+ ctx->pub_key = pub_key;
+ ctx->priv_key = priv_key;
+
+ /* done */
+ return(0);
+}
+
+static gcry_sexp_t
+xmlSecGCryptAsymKeyDataGetPublicKey(xmlSecKeyDataPtr data) {
+ xmlSecGCryptAsymKeyDataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL);
+ xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecGCryptAsymKeyDataSize), NULL);
+
+ ctx = xmlSecGCryptAsymKeyDataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, NULL);
+
+ return(ctx->pub_key);
+}
+
+static gcry_sexp_t
+xmlSecGCryptAsymKeyDataGetPrivateKey(xmlSecKeyDataPtr data) {
+ xmlSecGCryptAsymKeyDataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL);
+ xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecGCryptAsymKeyDataSize), NULL);
+
+ ctx = xmlSecGCryptAsymKeyDataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, NULL);
+
+ return(ctx->priv_key);
+}
+
+static int
+xmlSecGCryptAsymKeyDataGenerate(xmlSecKeyDataPtr data, const char * alg, xmlSecSize key_size) {
+ xmlSecGCryptAsymKeyDataCtxPtr ctx;
+ gcry_sexp_t key_spec = NULL;
+ gcry_sexp_t key_pair = NULL;
+ gcry_error_t err;
+ int ret;
+ int res = -1;
+
+ xmlSecAssert2(xmlSecKeyDataIsValid(data), -1);
+ xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecGCryptAsymKeyDataSize), -1);
+ xmlSecAssert2(alg != NULL, -1);
+ xmlSecAssert2(key_size > 0, -1);
+
+ ctx = xmlSecGCryptAsymKeyDataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, -1);
+
+ err = gcry_sexp_build(&key_spec, NULL,
+ "(genkey (%s (nbits %d)(transient-key)))",
+ alg, (int)key_size);
+ if((err != GPG_ERR_NO_ERROR) || (key_spec == NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_sexp_build(genkey)",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GCRYPT_REPORT_ERROR(err));
+ goto done;
+ }
+
+ err = gcry_pk_genkey(&key_pair, key_spec);
+ if((err != GPG_ERR_NO_ERROR) || (key_pair == NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_pk_genkey",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GCRYPT_REPORT_ERROR(err));
+ goto done;
+ }
+
+ ret = xmlSecGCryptAsymKeyDataAdoptKey(data, key_pair);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecGCryptAsymKeyDataAdopt",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "ret=%d", (int)ret);
+ goto done;
+ }
+ key_pair = NULL; /* now owned by data */
+
+ /* success */
+ res = 0;
+
+done:
+ if(key_spec != NULL) {
+ gcry_sexp_release(key_spec);
+ }
+ if(key_pair != NULL) {
+ gcry_sexp_release(key_pair);
+ }
+
+ return(res);
+}
+
+static xmlSecKeyDataType
+xmlSecGCryptAsymKeyDataGetType(xmlSecKeyDataPtr data) {
+ xmlSecGCryptAsymKeyDataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataIsValid(data), xmlSecKeyDataTypeUnknown);
+ xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecGCryptAsymKeyDataSize), xmlSecKeyDataTypeUnknown);
+
+ ctx = xmlSecGCryptAsymKeyDataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, xmlSecKeyDataTypeUnknown);
+
+ if((ctx->priv_key != NULL) && (ctx->pub_key != NULL)) {
+ return (xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic);
+ } else if(ctx->pub_key != NULL) {
+ return (xmlSecKeyDataTypePublic);
+ }
+
+ return (xmlSecKeyDataTypeUnknown);
+}
+
+static xmlSecSize
+xmlSecGCryptAsymKeyDataGetSize(xmlSecKeyDataPtr data) {
+ xmlSecGCryptAsymKeyDataCtxPtr ctx;
+
+ xmlSecAssert2(xmlSecKeyDataIsValid(data), xmlSecKeyDataTypeUnknown);
+ xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecGCryptAsymKeyDataSize), xmlSecKeyDataTypeUnknown);
+
+ ctx = xmlSecGCryptAsymKeyDataGetCtx(data);
+ xmlSecAssert2(ctx != NULL, 0);
+
+ /* use pub key since it is more often you have it than not */
+ return (ctx->pub_key != NULL) ? gcry_pk_get_nbits(ctx->pub_key) : 0;
+}
+
+/******************************************************************************
+ *
+ * helper functions
+ *
+ *****************************************************************************/
+static gcry_sexp_t
+xmlSecGCryptAsymSExpDup(gcry_sexp_t pKey) {
+ gcry_sexp_t res = NULL;
+ xmlSecByte *buf = NULL;
+ gcry_error_t err;
+ size_t size;
+
+ xmlSecAssert2(pKey != NULL, NULL);
+
+ size = gcry_sexp_sprint(pKey, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+ if(size == 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_sexp_sprint",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+ buf = (xmlSecByte *)xmlMalloc(size);
+ if(buf == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlMalloc",
+ XMLSEC_ERRORS_R_MALLOC_FAILED,
+ "size=%d", (int)size);
+ goto done;
+ }
+
+ size = gcry_sexp_sprint(pKey, GCRYSEXP_FMT_ADVANCED, buf, size);
+ if(size == 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_sexp_sprint",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ "size=%d", (int)size);
+ goto done;
+ }
+
+ err = gcry_sexp_new(&res, buf, size, 1);
+ if((err != GPG_ERR_NO_ERROR) || (res == NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_sexp_new",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GCRYPT_REPORT_ERROR(err));
+ goto done;
+ }
+
+done:
+ if(buf != NULL) {
+ xmlFree(buf);
+ }
+ return (res);
+}
+
+/**
+ * xmlSecGCryptNodeGetMpiValue:
+ * @cur: the poitner to an XML node.
+ *
+ * Converts the node content from CryptoBinary format
+ * (http://www.w3.org/TR/xmldsig-core/#sec-CryptoBinary)
+ * to a BIGNUM. If no BIGNUM buffer provided then a new
+ * BIGNUM is created (caller is responsible for freeing it).
+ *
+ * Returns: a pointer to MPI produced from CryptoBinary string
+ * or NULL if an error occurs.
+ */
+static gcry_mpi_t
+xmlSecGCryptNodeGetMpiValue(const xmlNodePtr cur) {
+ xmlSecBuffer buf;
+ gcry_mpi_t res = NULL;
+ gcry_error_t err;
+ int ret;
+
+ xmlSecAssert2(cur != NULL, NULL);
+
+ ret = xmlSecBufferInitialize(&buf, 128);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ return(NULL);
+ }
+
+ ret = xmlSecBufferBase64NodeContentRead(&buf, cur);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferBase64NodeContentRead",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecBufferFinalize(&buf);
+ return(NULL);
+ }
+
+ err = gcry_mpi_scan(&res, GCRYMPI_FMT_USG,
+ xmlSecBufferGetData(&buf),
+ xmlSecBufferGetSize(&buf),
+ NULL);
+ if((err != GPG_ERR_NO_ERROR) || (res == NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_mpi_scan",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GCRYPT_REPORT_ERROR(err));
+ xmlSecBufferFinalize(&buf);
+ return(NULL);
+ }
+
+ /* done */
+ xmlSecBufferFinalize(&buf);
+ return(res);
+}
+
+/**
+ * xmlSecGCryptNodeSetMpiValue:
+ * @cur: the pointer to an XML node.
+ * @a: the mpi value
+ * @addLineBreaks: if the flag is equal to 1 then
+ * linebreaks will be added before and after
+ * new buffer content.
+ *
+ * Converts MPI to CryptoBinary string
+ * (http://www.w3.org/TR/xmldsig-core/#sec-CryptoBinary)
+ * and sets it as the content of the given node. If the
+ * addLineBreaks is set then line breaks are added
+ * before and after the CryptoBinary string.
+ *
+ * Returns: 0 on success or -1 otherwise.
+ */
+static int
+xmlSecGCryptNodeSetMpiValue(xmlNodePtr cur, const gcry_mpi_t a, int addLineBreaks) {
+ xmlSecBuffer buf;
+ gcry_error_t err;
+ size_t written = 0;
+ int ret;
+
+ xmlSecAssert2(a != NULL, -1);
+ xmlSecAssert2(cur != NULL, -1);
+
+ written = 0;
+ err = gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &written, a);
+ if((err != GPG_ERR_NO_ERROR) || (written == 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_mpi_print",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GCRYPT_REPORT_ERROR(err));
+ return(-1);
+ }
+
+ ret = xmlSecBufferInitialize(&buf, written + 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferInitialize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "size=%d", (int)written + 1);
+ return(-1);
+ }
+
+ written = 0;
+ err = gcry_mpi_print(GCRYMPI_FMT_USG,
+ xmlSecBufferGetData(&buf),
+ xmlSecBufferGetMaxSize(&buf),
+ &written, a);
+ if((err != GPG_ERR_NO_ERROR) || (written == 0)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_mpi_print",
+ XMLSEC_ERRORS_R_CRYPTO_FAILED,
+ XMLSEC_GCRYPT_REPORT_ERROR(err));
+ xmlSecBufferFinalize(&buf);
+ return(-1);
+ }
+
+ ret = xmlSecBufferSetSize(&buf, written);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferSetSize",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "written=%d", (int)written);
+ xmlSecBufferFinalize(&buf);
+ return(-1);
+ }
+
+ if(addLineBreaks) {
+ xmlNodeSetContent(cur, xmlSecStringCR);
+ } else {
+ xmlNodeSetContent(cur, xmlSecStringEmpty);
+ }
+
+ ret = xmlSecBufferBase64NodeContentWrite(&buf, cur, xmlSecBase64GetDefaultLineSize());
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "xmlSecBufferBase64NodeContentWrite",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ xmlSecBufferFinalize(&buf);
+ return(-1);
+ }
+
+ if(addLineBreaks) {
+ xmlNodeAddContent(cur, xmlSecStringCR);
+ }
+
+ xmlSecBufferFinalize(&buf);
+ return(0);
+}
+
+/**
+ * xmlSecGCryptNodeSetSExpTokValue:
+ * @cur: the pointer to an XML node.
+ * @sexp: the sexp
+ * @tok: the token
+ * @addLineBreaks: if the flag is equal to 1 then
+ * linebreaks will be added before and after
+ * new buffer content.
+ *
+ * Converts MPI to CryptoBinary string
+ * (http://www.w3.org/TR/xmldsig-core/#sec-CryptoBinary)
+ * and sets it as the content of the given node. If the
+ * addLineBreaks is set then line breaks are added
+ * before and after the CryptoBinary string.
+ *
+ * Returns: 0 on success or -1 otherwise.
+ */
+static int
+xmlSecGCryptNodeSetSExpTokValue(xmlNodePtr cur, const gcry_sexp_t sexp,
+ const char * tok, int addLineBreaks)
+{
+ gcry_sexp_t val = NULL;
+ gcry_mpi_t mpi = NULL;
+ int res = -1;
+
+ xmlSecAssert2(cur != NULL, -1);
+ xmlSecAssert2(sexp != NULL, -1);
+ xmlSecAssert2(tok != NULL, -1);
+
+ val = gcry_sexp_find_token(sexp, tok, 0);
+ if(val == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_sexp_find_token",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "tok=%s",
+ xmlSecErrorsSafeString(tok));
+ goto done;
+ }
+
+ mpi = gcry_sexp_nth_mpi(val, 1, GCRYMPI_FMT_USG);
+ if(mpi == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ NULL,
+ "gcry_sexp_nth_mpi",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "tok=%s",
+ xmlSecErrorsSafeString(tok));
+ goto done;
+ }
+
+ /* almost done */
+ res = xmlSecGCryptNodeSetMpiValue(cur, mpi, addLineBreaks);
+
+done:
+ if(mpi != NULL) {
+ gcry_mpi_release(mpi);
+ }
+ if(val != NULL) {
+ gcry_sexp_release(val);
+ }
+
+ return(res);
+}
+
+#ifndef XMLSEC_NO_DSA
+/**************************************************************************
+ *
+ * <dsig:DSAKeyValue> processing
+ *
+ *
+ * The DSAKeyValue Element (http://www.w3.org/TR/xmldsig-core/#sec-DSAKeyValue)
+ *
+ * DSA keys and the DSA signature algorithm are specified in [DSS].
+ * DSA public key values can have the following fields:
+ *
+ * * P - a prime modulus meeting the [DSS] requirements
+ * * Q - an integer in the range 2**159 < Q < 2**160 which is a prime
+ * divisor of P-1
+ * * G - an integer with certain properties with respect to P and Q
+ * * Y - G**X mod P (where X is part of the private key and not made
+ * public)
+ * * J - (P - 1) / Q
+ * * seed - a DSA prime generation seed
+ * * pgenCounter - a DSA prime generation counter
+ *
+ * Parameter J is available for inclusion solely for efficiency as it is
+ * calculatable from P and Q. Parameters seed and pgenCounter are used in the
+ * DSA prime number generation algorithm specified in [DSS]. As such, they are
+ * optional but must either both be present or both be absent. This prime
+ * generation algorithm is designed to provide assurance that a weak prime is
+ * not being used and it yields a P and Q value. Parameters P, Q, and G can be
+ * public and common to a group of users. They might be known from application
+ * context. As such, they are optional but P and Q must either both appear or
+ * both be absent. If all of P, Q, seed, and pgenCounter are present,
+ * implementations are not required to check if they are consistent and are
+ * free to use either P and Q or seed and pgenCounter. All parameters are
+ * encoded as base64 [MIME] values.
+ *
+ * Arbitrary-length integers (e.g. "bignums" such as RSA moduli) are
+ * represented in XML as octet strings as defined by the ds:CryptoBinary type.
+ *
+ * Schema Definition:
+ *
+ * <element name="DSAKeyValue" type="ds:DSAKeyValueType"/>
+ * <complexType name="DSAKeyValueType">
+ * <sequence>
+ * <sequence minOccurs="0">
+ * <element name="P" type="ds:CryptoBinary"/>
+ * <element name="Q" type="ds:CryptoBinary"/>
+ * </sequence>
+ * <element name="G" type="ds:CryptoBinary" minOccurs="0"/>
+ * <element name="Y" type="ds:CryptoBinary"/>
+ * <element name="J" type="ds:CryptoBinary" minOccurs="0"/>
+ * <sequence minOccurs="0">
+ * <element name="Seed" type="ds:CryptoBinary"/>
+ * <element name="PgenCounter" type="ds:CryptoBinary"/>
+ * </sequence>
+ * </sequence>
+ * </complexType>
+ *
+ * DTD Definition:
+ *
+ * <!ELEMENT DSAKeyValue ((P, Q)?, G?, Y, J?, (Seed, PgenCounter)?) >
+ * <!ELEMENT P (#PCDATA) >
+ * <!ELEMENT Q (#PCDATA) >
+ * <!ELEMENT G (#PCDATA) >
+ * <!ELEMENT Y (#PCDATA) >
+ * <!ELEMENT J (#PCDATA) >
+ * <!ELEMENT Seed (#PCDATA) >
+ * <!ELEMENT PgenCounter (#PCDATA) >
+ *
+ * ============================================================================
+ *
+ * To support reading/writing private keys an X element added (before Y).
+ * todo: The current implementation does not support Seed and PgenCounter!
+ * by this the P, Q and G are *required*!
+ *
+ *************************************************************************/
+static int xmlSecGCryptKeyDataDsaInitialize (xmlSecKeyDataPtr data);
+static int xmlSecGCryptKeyDataDsaDuplicate (xmlSecKeyDataPtr dst,
+ xmlSecKeyDataPtr src);
+static void xmlSecGCryptKeyDataDsaFinalize (xmlSecKeyDataPtr data);
+static int xmlSecGCryptKeyDataDsaXmlRead (xmlSecKeyDataId id,
+ xmlSecKeyPtr key,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGCryptKeyDataDsaXmlWrite (xmlSecKeyDataId id,
+ xmlSecKeyPtr key,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGCryptKeyDataDsaGenerate (xmlSecKeyDataPtr data,
+ xmlSecSize sizeBits,
+ xmlSecKeyDataType type);
+
+static xmlSecKeyDataType xmlSecGCryptKeyDataDsaGetType (xmlSecKeyDataPtr data);
+static xmlSecSize xmlSecGCryptKeyDataDsaGetSize (xmlSecKeyDataPtr data);
+static void xmlSecGCryptKeyDataDsaDebugDump (xmlSecKeyDataPtr data,
+ FILE* output);
+static void xmlSecGCryptKeyDataDsaDebugXmlDump (xmlSecKeyDataPtr data,
+ FILE* output);
+
+static xmlSecKeyDataKlass xmlSecGCryptKeyDataDsaKlass = {
+ sizeof(xmlSecKeyDataKlass),
+ xmlSecGCryptAsymKeyDataSize,
+
+ /* data */
+ xmlSecNameDSAKeyValue,
+ xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml,
+ /* xmlSecKeyDataUsage usage; */
+ xmlSecHrefDSAKeyValue, /* const xmlChar* href; */
+ xmlSecNodeDSAKeyValue, /* const xmlChar* dataNodeName; */
+ xmlSecDSigNs, /* const xmlChar* dataNodeNs; */
+
+ /* constructors/destructor */
+ xmlSecGCryptKeyDataDsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */
+ xmlSecGCryptKeyDataDsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */
+ xmlSecGCryptKeyDataDsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */
+ xmlSecGCryptKeyDataDsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */
+
+ /* get info */
+ xmlSecGCryptKeyDataDsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */
+ xmlSecGCryptKeyDataDsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */
+ NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */
+
+ /* read/write */
+ xmlSecGCryptKeyDataDsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */
+ xmlSecGCryptKeyDataDsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */
+ NULL, /* xmlSecKeyDataBinReadMethod binRead; */
+ NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */
+
+ /* debug */
+ xmlSecGCryptKeyDataDsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */
+ xmlSecGCryptKeyDataDsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+ /* reserved for the future */
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+/**
+ * xmlSecGCryptKeyDataDsaGetKlass:
+ *
+ * The DSA key data klass.
+ *
+ * Returns: pointer to DSA key data klass.
+ */
+xmlSecKeyDataId
+xmlSecGCryptKeyDataDsaGetKlass(void) {
+ return(&xmlSecGCryptKeyDataDsaKlass);
+}
+
+/**
+ * xmlSecGCryptKeyDataDsaAdoptKey:
+ * @data: the pointer to DSA key data.
+ * @dsa_key: the pointer to GCrypt DSA key.
+ *
+ * Sets the value of DSA key data.
+ *
+ * Returns: 0 on success or a negative value otherwise.
+ */
+int
+xmlSecGCryptKeyDataDsaAdoptKey(xmlSecKeyDataPtr data, gcry_sexp_t dsa_key) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId), -1);
+ xmlSecAssert2(dsa_key != NULL, -1);
+
+ return xmlSecGCryptAsymKeyDataAdoptKey(data, dsa_key);
+}
+
+
+/**
+ * xmlSecGCryptKeyDataDsaAdoptKeyPair:
+ * @data: the pointer to DSA key data.
+ * @pub_key: the pointer to GCrypt DSA pub key.
+ * @priv_key: the pointer to GCrypt DSA priv key.
+ *
+ * Sets the value of DSA key data.
+ *
+ * Returns: 0 on success or a negative value otherwise.
+ */
+int
+xmlSecGCryptKeyDataDsaAdoptKeyPair(xmlSecKeyDataPtr data, gcry_sexp_t pub_key, gcry_sexp_t priv_key) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId), -1);
+ xmlSecAssert2(pub_key != NULL, -1);
+
+ return xmlSecGCryptAsymKeyDataAdoptKeyPair(data, pub_key, priv_key);
+}
+
+/**
+ * xmlSecGCryptKeyDataDsaGetPublicKey:
+ * @data: the pointer to DSA key data.
+ *
+ * Gets the GCrypt DSA public key from DSA key data.
+ *
+ * Returns: pointer to GCrypt public DSA key or NULL if an error occurs.
+ */
+gcry_sexp_t
+xmlSecGCryptKeyDataDsaGetPublicKey(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId), NULL);
+ return xmlSecGCryptAsymKeyDataGetPublicKey(data);
+}
+
+/**
+ * xmlSecGCryptKeyDataDsaGetPrivateKey:
+ * @data: the pointer to DSA key data.
+ *
+ * Gets the GCrypt DSA private key from DSA key data.
+ *
+ * Returns: pointer to GCrypt private DSA key or NULL if an error occurs.
+ */
+gcry_sexp_t
+xmlSecGCryptKeyDataDsaGetPrivateKey(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId), NULL);
+ return xmlSecGCryptAsymKeyDataGetPrivateKey(data);
+}
+
+static int
+xmlSecGCryptKeyDataDsaInitialize(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId), -1);
+
+ return(xmlSecGCryptAsymKeyDataInitialize(data));
+}
+
+static int
+xmlSecGCryptKeyDataDsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecGCryptKeyDataDsaId), -1);
+ xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecGCryptKeyDataDsaId), -1);
+
+ return(xmlSecGCryptAsymKeyDataDuplicate(dst, src));
+}
+
+static void
+xmlSecGCryptKeyDataDsaFinalize(xmlSecKeyDataPtr data) {
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId));
+
+ xmlSecGCryptAsymKeyDataFinalize(data);
+}
+
+static int
+xmlSecGCryptKeyDataDsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId), -1);
+ xmlSecAssert2(sizeBits > 0, -1);
+
+ return xmlSecGCryptAsymKeyDataGenerate(data, "dsa", sizeBits);
+}
+
+static xmlSecKeyDataType
+xmlSecGCryptKeyDataDsaGetType(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId), xmlSecKeyDataTypeUnknown);
+
+ return xmlSecGCryptAsymKeyDataGetType(data);
+}
+
+static xmlSecSize
+xmlSecGCryptKeyDataDsaGetSize(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId), 0);
+
+ return xmlSecGCryptAsymKeyDataGetSize(data);
+}
+
+static void
+xmlSecGCryptKeyDataDsaDebugDump(xmlSecKeyDataPtr data, FILE* output) {
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId));
+ xmlSecAssert(output != NULL);
+
+ fprintf(output, "=== dsa key: size = %d\n",
+ xmlSecGCryptKeyDataDsaGetSize(data));
+}
+
+static void
+xmlSecGCryptKeyDataDsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) {
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataDsaId));
+ xmlSecAssert(output != NULL);
+
+ fprintf(output, "<DSAKeyValue size=\"%d\" />\n",
+ xmlSecGCryptKeyDataDsaGetSize(data));
+}
+
+static int
+xmlSecGCryptKeyDataDsaXmlRead(xmlSecKeyDataId id,
+ xmlSecKeyPtr key,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx)
+{
+ xmlNodePtr cur;
+ xmlSecKeyDataPtr data = NULL;
+ gcry_mpi_t p = NULL;
+ gcry_mpi_t q = NULL;
+ gcry_mpi_t g = NULL;
+ gcry_mpi_t x = NULL;
+ gcry_mpi_t y = NULL;
+ gcry_sexp_t pub_key = NULL;
+ gcry_sexp_t priv_key = NULL;
+ gcry_error_t err;
+ int res = -1;
+ int ret;
+
+ xmlSecAssert2(id == xmlSecGCryptKeyDataDsaId, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ if(xmlSecKeyGetValue(key) != NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_KEY_DATA,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+ cur = xmlSecGetNextElementNode(node->children);
+
+ /* first is P node. It is REQUIRED because we do not support Seed and PgenCounter*/
+ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAP, xmlSecDSigNs))) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_INVALID_NODE,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAP));
+ goto done;
+ }
+ p = xmlSecGCryptNodeGetMpiValue(cur);
+ if(p == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeGetMpiValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAP));
+ goto done;
+ }
+ cur = xmlSecGetNextElementNode(cur->next);
+
+ /* next is Q node. It is REQUIRED because we do not support Seed and PgenCounter*/
+ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAQ, xmlSecDSigNs))) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_INVALID_NODE,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAQ));
+ goto done;
+ }
+ q = xmlSecGCryptNodeGetMpiValue(cur);
+ if(q == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeGetMpiValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAQ));
+ goto done;
+ }
+ cur = xmlSecGetNextElementNode(cur->next);
+
+ /* next is G node. It is REQUIRED because we do not support Seed and PgenCounter*/
+ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAG, xmlSecDSigNs))) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_INVALID_NODE,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAG));
+ goto done;
+ }
+ g = xmlSecGCryptNodeGetMpiValue(cur);
+ if(g == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeGetMpiValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAG));
+ goto done;
+ }
+ cur = xmlSecGetNextElementNode(cur->next);
+
+ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAX, xmlSecNs))) {
+ /* next is X node. It is REQUIRED for private key but
+ * we are not sure exactly what do we read */
+ x = xmlSecGCryptNodeGetMpiValue(cur);
+ if(x == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeGetMpiValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAX));
+ goto done;
+ }
+ cur = xmlSecGetNextElementNode(cur->next);
+ }
+
+ /* next is Y node. */
+ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAY, xmlSecDSigNs))) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_INVALID_NODE,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAY));
+ goto done;
+ }
+ y = xmlSecGCryptNodeGetMpiValue(cur);
+ if(y == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeGetMpiValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s", xmlSecErrorsSafeString(xmlSecNodeDSAY));
+ goto done;
+ }
+ cur = xmlSecGetNextElementNode(cur->next);
+
+ /* todo: add support for J */
+ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAJ, xmlSecDSigNs))) {
+ cur = xmlSecGetNextElementNode(cur->next);
+ }
+
+ /* todo: add support for seed */
+ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSASeed, xmlSecDSigNs))) {
+ cur = xmlSecGetNextElementNode(cur->next);
+ }
+
+ /* todo: add support for pgencounter */
+ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAPgenCounter, xmlSecDSigNs))) {
+ cur = xmlSecGetNextElementNode(cur->next);
+ }
+
+ if(cur != NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_UNEXPECTED_NODE,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+
+ /* construct pub/priv key pairs */
+ err = gcry_sexp_build(&pub_key, NULL,
+ "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
+ p, q, g, y);
+ if((err != GPG_ERR_NO_ERROR) || (pub_key == NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "gcry_sexp_build(public)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_GCRYPT_REPORT_ERROR(err));
+ goto done;
+ }
+ if(x != NULL) {
+ err = gcry_sexp_build(&priv_key, NULL,
+ "(private-key(dsa(p%m)(q%m)(g%m)(x%m)(y%m)))",
+ p, q, g, x, y);
+ if((err != GPG_ERR_NO_ERROR) || (priv_key == NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "gcry_sexp_build(private)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_GCRYPT_REPORT_ERROR(err));
+ goto done;
+ }
+ }
+
+ /* create key data */
+ data = xmlSecKeyDataCreate(id);
+ if(data == NULL ) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecKeyDataCreate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+ ret = xmlSecGCryptKeyDataDsaAdoptKeyPair(data, pub_key, priv_key);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGCryptKeyDataDsaAdoptKeyPair",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ pub_key = NULL; /* pub_key is owned by data now */
+ priv_key = NULL; /* priv_key is owned by data now */
+
+ /* set key */
+ ret = xmlSecKeySetValue(key, data);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecKeySetValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ data = NULL; /* data is owned by key now */
+
+ /* success */
+ res = 0;
+
+done:
+ /* cleanup */
+ if(p != NULL) {
+ gcry_mpi_release(p);
+ }
+
+ if(q != NULL) {
+ gcry_mpi_release(q);
+ }
+
+ if(g != NULL) {
+ gcry_mpi_release(g);
+ }
+
+ if(x != NULL) {
+ gcry_mpi_release(x);
+ }
+
+ if(y != NULL) {
+ gcry_mpi_release(y);
+ }
+
+ if(pub_key != NULL) {
+ gcry_sexp_release(pub_key);
+ }
+
+ if(priv_key != NULL) {
+ gcry_sexp_release(priv_key);
+ }
+
+ if(data != NULL) {
+ xmlSecKeyDataDestroy(data);
+ }
+ return(res);
+}
+
+static int
+xmlSecGCryptKeyDataDsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key,
+ xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlNodePtr cur;
+ gcry_sexp_t pub_priv_key;
+ gcry_sexp_t dsa = NULL;
+ int private = 0;
+ int res = -1;
+ int ret;
+
+ xmlSecAssert2(id == xmlSecGCryptKeyDataDsaId, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecGCryptKeyDataDsaId), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) {
+ /* we can have only private key or public key */
+ return(0);
+ }
+
+ /* find the private or public key */
+ pub_priv_key = xmlSecGCryptKeyDataDsaGetPrivateKey(xmlSecKeyGetValue(key));
+ if(pub_priv_key == NULL) {
+ pub_priv_key = xmlSecGCryptKeyDataDsaGetPublicKey(xmlSecKeyGetValue(key));
+ if(pub_priv_key == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptKeyDataDsaGetPublicKey()",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ } else {
+ private = 1;
+ }
+
+ dsa = gcry_sexp_find_token(pub_priv_key, "dsa", 0);
+ if(dsa == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "gcry_sexp_find_token(dsa)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+ /* first is P node */
+ cur = xmlSecAddChild(node, xmlSecNodeDSAP, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAP));
+ goto done;
+ }
+ ret = xmlSecGCryptNodeSetSExpTokValue(cur, dsa, "p", 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeSetSExpTokValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAP));
+ goto done;
+ }
+
+ /* next is Q node. */
+ cur = xmlSecAddChild(node, xmlSecNodeDSAQ, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAQ));
+ goto done;
+ }
+ ret = xmlSecGCryptNodeSetSExpTokValue(cur, dsa, "q", 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeSetSExpTokValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAQ));
+ goto done;
+ }
+
+ /* next is G node. */
+ cur = xmlSecAddChild(node, xmlSecNodeDSAG, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAG));
+ goto done;
+ }
+ ret = xmlSecGCryptNodeSetSExpTokValue(cur, dsa, "g", 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeSetSExpTokValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAG));
+ goto done;
+ }
+
+ /* next is X node: write it ONLY for private keys and ONLY if it is requested */
+ if(((keyInfoCtx->keyReq.keyType & xmlSecKeyDataTypePrivate) != 0) && (private != 0)) {
+ cur = xmlSecAddChild(node, xmlSecNodeDSAX, xmlSecNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAX));
+ goto done;
+ }
+ ret = xmlSecGCryptNodeSetSExpTokValue(cur, dsa, "x", 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeSetSExpTokValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAX));
+ goto done;
+ }
+ }
+
+ /* next is Y node. */
+ cur = xmlSecAddChild(node, xmlSecNodeDSAY, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAY));
+ goto done;
+ }
+ ret = xmlSecGCryptNodeSetSExpTokValue(cur, dsa, "y", 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeSetSExpTokValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeDSAY));
+ goto done;
+ }
+
+ /* success */
+ res = 0;
+
+done:
+ if(dsa != NULL) {
+ gcry_sexp_release(dsa);
+ }
+
+ return(res);
+}
+
+#endif /* XMLSEC_NO_DSA */
+
+
+#ifndef XMLSEC_NO_RSA
+/**************************************************************************
+ *
+ * <dsig:RSAKeyValue> processing
+ *
+ * http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
+ * The RSAKeyValue Element
+ *
+ * RSA key values have two fields: Modulus and Exponent.
+ *
+ * <RSAKeyValue>
+ * <Modulus>xA7SEU+e0yQH5rm9kbCDN9o3aPIo7HbP7tX6WOocLZAtNfyxSZDU16ksL6W
+ * jubafOqNEpcwR3RdFsT7bCqnXPBe5ELh5u4VEy19MzxkXRgrMvavzyBpVRgBUwUlV
+ * 5foK5hhmbktQhyNdy/6LpQRhDUDsTvK+g9Ucj47es9AQJ3U=
+ * </Modulus>
+ * <Exponent>AQAB</Exponent>
+ * </RSAKeyValue>
+ *
+ * Arbitrary-length integers (e.g. "bignums" such as RSA moduli) are
+ * represented in XML as octet strings as defined by the ds:CryptoBinary type.
+ *
+ * Schema Definition:
+ *
+ * <element name="RSAKeyValue" type="ds:RSAKeyValueType"/>
+ * <complexType name="RSAKeyValueType">
+ * <sequence>
+ * <element name="Modulus" type="ds:CryptoBinary"/>
+ * <element name="Exponent" type="ds:CryptoBinary"/>
+ * </sequence>
+ * </complexType>
+ *
+ * DTD Definition:
+ *
+ * <!ELEMENT RSAKeyValue (Modulus, Exponent) >
+ * <!ELEMENT Modulus (#PCDATA) >
+ * <!ELEMENT Exponent (#PCDATA) >
+ *
+ * ============================================================================
+ *
+ * To support reading/writing private keys an PrivateExponent element is added
+ * to the end
+ *
+ *************************************************************************/
+
+static int xmlSecGCryptKeyDataRsaInitialize (xmlSecKeyDataPtr data);
+static int xmlSecGCryptKeyDataRsaDuplicate (xmlSecKeyDataPtr dst,
+ xmlSecKeyDataPtr src);
+static void xmlSecGCryptKeyDataRsaFinalize (xmlSecKeyDataPtr data);
+static int xmlSecGCryptKeyDataRsaXmlRead (xmlSecKeyDataId id,
+ xmlSecKeyPtr key,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGCryptKeyDataRsaXmlWrite (xmlSecKeyDataId id,
+ xmlSecKeyPtr key,
+ xmlNodePtr node,
+ xmlSecKeyInfoCtxPtr keyInfoCtx);
+static int xmlSecGCryptKeyDataRsaGenerate (xmlSecKeyDataPtr data,
+ xmlSecSize sizeBits,
+ xmlSecKeyDataType type);
+
+static xmlSecKeyDataType xmlSecGCryptKeyDataRsaGetType (xmlSecKeyDataPtr data);
+static xmlSecSize xmlSecGCryptKeyDataRsaGetSize (xmlSecKeyDataPtr data);
+static void xmlSecGCryptKeyDataRsaDebugDump (xmlSecKeyDataPtr data,
+ FILE* output);
+static void xmlSecGCryptKeyDataRsaDebugXmlDump (xmlSecKeyDataPtr data,
+ FILE* output);
+static xmlSecKeyDataKlass xmlSecGCryptKeyDataRsaKlass = {
+ sizeof(xmlSecKeyDataKlass),
+ xmlSecGCryptAsymKeyDataSize,
+
+ /* data */
+ xmlSecNameRSAKeyValue,
+ xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml,
+ /* xmlSecKeyDataUsage usage; */
+ xmlSecHrefRSAKeyValue, /* const xmlChar* href; */
+ xmlSecNodeRSAKeyValue, /* const xmlChar* dataNodeName; */
+ xmlSecDSigNs, /* const xmlChar* dataNodeNs; */
+
+ /* constructors/destructor */
+ xmlSecGCryptKeyDataRsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */
+ xmlSecGCryptKeyDataRsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */
+ xmlSecGCryptKeyDataRsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */
+ xmlSecGCryptKeyDataRsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */
+
+ /* get info */
+ xmlSecGCryptKeyDataRsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */
+ xmlSecGCryptKeyDataRsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */
+ NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */
+
+ /* read/write */
+ xmlSecGCryptKeyDataRsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */
+ xmlSecGCryptKeyDataRsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */
+ NULL, /* xmlSecKeyDataBinReadMethod binRead; */
+ NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */
+
+ /* debug */
+ xmlSecGCryptKeyDataRsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */
+ xmlSecGCryptKeyDataRsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */
+
+ /* reserved for the future */
+ NULL, /* void* reserved0; */
+ NULL, /* void* reserved1; */
+};
+
+/**
+ * xmlSecGCryptKeyDataRsaGetKlass:
+ *
+ * The GCrypt RSA key data klass.
+ *
+ * Returns: pointer to GCrypt RSA key data klass.
+ */
+xmlSecKeyDataId
+xmlSecGCryptKeyDataRsaGetKlass(void) {
+ return(&xmlSecGCryptKeyDataRsaKlass);
+}
+
+/**
+ * xmlSecGCryptKeyDataRsaAdoptKey:
+ * @data: the pointer to RSA key data.
+ * @rsa_key: the pointer to GCrypt RSA key.
+ *
+ * Sets the value of RSA key data.
+ *
+ * Returns: 0 on success or a negative value otherwise.
+ */
+int
+xmlSecGCryptKeyDataRsaAdoptKey(xmlSecKeyDataPtr data, gcry_sexp_t rsa_key) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId), -1);
+ xmlSecAssert2(rsa_key != NULL, -1);
+
+ return xmlSecGCryptAsymKeyDataAdoptKey(data, rsa_key);
+}
+
+
+/**
+ * xmlSecGCryptKeyDataRsaAdoptKeyPair:
+ * @data: the pointer to RSA key data.
+ * @pub_key: the pointer to GCrypt RSA pub key.
+ * @priv_key: the pointer to GCrypt RSA priv key.
+ *
+ * Sets the value of RSA key data.
+ *
+ * Returns: 0 on success or a negative value otherwise.
+ */
+int
+xmlSecGCryptKeyDataRsaAdoptKeyPair(xmlSecKeyDataPtr data, gcry_sexp_t pub_key, gcry_sexp_t priv_key) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId), -1);
+ xmlSecAssert2(pub_key != NULL, -1);
+
+ return xmlSecGCryptAsymKeyDataAdoptKeyPair(data, pub_key, priv_key);
+}
+
+/**
+ * xmlSecGCryptKeyDataRsaGetPublicKey:
+ * @data: the pointer to RSA key data.
+ *
+ * Gets the GCrypt RSA public key from RSA key data.
+ *
+ * Returns: pointer to GCrypt public RSA key or NULL if an error occurs.
+ */
+gcry_sexp_t
+xmlSecGCryptKeyDataRsaGetPublicKey(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId), NULL);
+ return xmlSecGCryptAsymKeyDataGetPublicKey(data);
+}
+
+/**
+ * xmlSecGCryptKeyDataRsaGetPrivateKey:
+ * @data: the pointer to RSA key data.
+ *
+ * Gets the GCrypt RSA private key from RSA key data.
+ *
+ * Returns: pointer to GCrypt private RSA key or NULL if an error occurs.
+ */
+gcry_sexp_t
+xmlSecGCryptKeyDataRsaGetPrivateKey(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId), NULL);
+ return xmlSecGCryptAsymKeyDataGetPrivateKey(data);
+}
+
+static int
+xmlSecGCryptKeyDataRsaInitialize(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId), -1);
+
+ return(xmlSecGCryptAsymKeyDataInitialize(data));
+}
+
+static int
+xmlSecGCryptKeyDataRsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecGCryptKeyDataRsaId), -1);
+ xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecGCryptKeyDataRsaId), -1);
+
+ return(xmlSecGCryptAsymKeyDataDuplicate(dst, src));
+}
+
+static void
+xmlSecGCryptKeyDataRsaFinalize(xmlSecKeyDataPtr data) {
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId));
+
+ xmlSecGCryptAsymKeyDataFinalize(data);
+}
+
+static int
+xmlSecGCryptKeyDataRsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId), -1);
+ xmlSecAssert2(sizeBits > 0, -1);
+
+ return xmlSecGCryptAsymKeyDataGenerate(data, "rsa", sizeBits);
+}
+
+static xmlSecKeyDataType
+xmlSecGCryptKeyDataRsaGetType(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId), xmlSecKeyDataTypeUnknown);
+
+ return xmlSecGCryptAsymKeyDataGetType(data);
+}
+
+static xmlSecSize
+xmlSecGCryptKeyDataRsaGetSize(xmlSecKeyDataPtr data) {
+ xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId), 0);
+
+ return xmlSecGCryptAsymKeyDataGetSize(data);
+}
+
+static void
+xmlSecGCryptKeyDataRsaDebugDump(xmlSecKeyDataPtr data, FILE* output) {
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId));
+ xmlSecAssert(output != NULL);
+
+ fprintf(output, "=== rsa key: size = %d\n",
+ xmlSecGCryptKeyDataRsaGetSize(data));
+}
+
+static void
+xmlSecGCryptKeyDataRsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) {
+ xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecGCryptKeyDataRsaId));
+ xmlSecAssert(output != NULL);
+
+ fprintf(output, "<RSAKeyValue size=\"%d\" />\n",
+ xmlSecGCryptKeyDataRsaGetSize(data));
+}
+
+static int
+xmlSecGCryptKeyDataRsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key,
+ xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlNodePtr cur;
+ xmlSecKeyDataPtr data = NULL;
+ gcry_mpi_t n = NULL;
+ gcry_mpi_t e = NULL;
+ gcry_mpi_t d = NULL;
+ gcry_sexp_t pub_key = NULL;
+ gcry_sexp_t priv_key = NULL;
+ gcry_error_t err;
+ int res = -1;
+ int ret;
+
+ xmlSecAssert2(id == xmlSecGCryptKeyDataRsaId, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ if(xmlSecKeyGetValue(key) != NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ NULL,
+ XMLSEC_ERRORS_R_INVALID_KEY_DATA,
+ "key already has a value");
+ goto done;
+ }
+
+ cur = xmlSecGetNextElementNode(node->children);
+
+ /* first is Modulus node. It is REQUIRED */
+ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRSAModulus, xmlSecDSigNs))) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_INVALID_NODE,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAModulus));
+ goto done;
+ }
+ n = xmlSecGCryptNodeGetMpiValue(cur);
+ if(n == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeGetMpiValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAModulus));
+ goto done;
+ }
+ cur = xmlSecGetNextElementNode(cur->next);
+
+ /* next is Exponent node. It is REQUIRED */
+ if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRSAExponent, xmlSecDSigNs))) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_INVALID_NODE,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAExponent));
+ goto done;
+ }
+ e = xmlSecGCryptNodeGetMpiValue(cur);
+ if(e == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeGetMpiValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAExponent));
+ goto done;
+ }
+ cur = xmlSecGetNextElementNode(cur->next);
+
+ if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeRSAPrivateExponent, xmlSecNs))) {
+ /* next is PrivateExponent node. It is REQUIRED for private key */
+ d = xmlSecGCryptNodeGetMpiValue(cur);
+ if(d == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeGetMpiValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAPrivateExponent));
+ goto done;
+ }
+ cur = xmlSecGetNextElementNode(cur->next);
+ }
+
+ if(cur != NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ xmlSecErrorsSafeString(xmlSecNodeGetName(cur)),
+ XMLSEC_ERRORS_R_INVALID_NODE,
+ "no nodes expected");
+ goto done;
+ }
+
+ /* construct pub/priv key pairs */
+ err = gcry_sexp_build(&pub_key, NULL,
+ "(public-key(rsa(n%m)(e%m)))",
+ n, e);
+ if((err != GPG_ERR_NO_ERROR) || (pub_key == NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "gcry_sexp_build(public)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_GCRYPT_REPORT_ERROR(err));
+ goto done;
+ }
+ if(d != NULL) {
+ err = gcry_sexp_build(&priv_key, NULL,
+ "(private-key(rsa(n%m)(e%m)(d%m)))",
+ n, e, d);
+ if((err != GPG_ERR_NO_ERROR) || (priv_key == NULL)) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "gcry_sexp_build(private)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_GCRYPT_REPORT_ERROR(err));
+ goto done;
+ }
+ }
+
+
+ /* create key data */
+ data = xmlSecKeyDataCreate(id);
+ if(data == NULL ) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecKeyDataCreate",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+ ret = xmlSecGCryptKeyDataRsaAdoptKeyPair(data, pub_key, priv_key);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecGCryptKeyDataRsaAdoptKeyPair",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ pub_key = NULL; /* pub_key is owned by data now */
+ priv_key = NULL; /* priv_key is owned by data now */
+
+ /* set key */
+ ret = xmlSecKeySetValue(key, data);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)),
+ "xmlSecKeySetValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ data = NULL; /* data is owned by key now */
+
+
+ /* success */
+ res = 0;
+
+done:
+ /* cleanup */
+ if(n != NULL) {
+ gcry_mpi_release(n);
+ }
+
+ if(e != NULL) {
+ gcry_mpi_release(e);
+ }
+
+ if(d != NULL) {
+ gcry_mpi_release(d);
+ }
+
+ if(pub_key != NULL) {
+ gcry_sexp_release(pub_key);
+ }
+
+ if(priv_key != NULL) {
+ gcry_sexp_release(priv_key);
+ }
+
+ if(data != NULL) {
+ xmlSecKeyDataDestroy(data);
+ }
+ return(res);
+
+}
+
+static int
+xmlSecGCryptKeyDataRsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key,
+ xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) {
+ xmlNodePtr cur;
+ gcry_sexp_t pub_priv_key;
+ gcry_sexp_t rsa = NULL;
+ int private = 0;
+ int res = -1;
+ int ret;
+
+ xmlSecAssert2(id == xmlSecGCryptKeyDataRsaId, -1);
+ xmlSecAssert2(key != NULL, -1);
+ xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecGCryptKeyDataRsaId), -1);
+ xmlSecAssert2(node != NULL, -1);
+ xmlSecAssert2(keyInfoCtx != NULL, -1);
+
+ if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) {
+ /* we can have only private key or public key */
+ return(0);
+ }
+
+ /* find the private or public key */
+ pub_priv_key = xmlSecGCryptKeyDataRsaGetPrivateKey(xmlSecKeyGetValue(key));
+ if(pub_priv_key == NULL) {
+ pub_priv_key = xmlSecGCryptKeyDataRsaGetPublicKey(xmlSecKeyGetValue(key));
+ if(pub_priv_key == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptKeyDataRsaGetPublicKey()",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+ } else {
+ private = 1;
+ }
+
+ rsa = gcry_sexp_find_token(pub_priv_key, "rsa", 0);
+ if(rsa == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "gcry_sexp_find_token(rsa)",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ XMLSEC_ERRORS_NO_MESSAGE);
+ goto done;
+ }
+
+ /* first is Modulus node */
+ cur = xmlSecAddChild(node, xmlSecNodeRSAModulus, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAModulus));
+ goto done;
+ }
+ ret = xmlSecGCryptNodeSetSExpTokValue(cur, rsa, "n", 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeSetSExpTokValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAModulus));
+ goto done;
+ }
+
+ /* next is Exponent node. */
+ cur = xmlSecAddChild(node, xmlSecNodeRSAExponent, xmlSecDSigNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAExponent));
+ goto done;
+ }
+ ret = xmlSecGCryptNodeSetSExpTokValue(cur, rsa, "e", 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeSetSExpTokValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAExponent));
+ goto done;
+ }
+
+ /* next is PrivateExponent node: write it ONLY for private keys and ONLY if it is requested */
+ if(((keyInfoCtx->keyReq.keyType & xmlSecKeyDataTypePrivate) != 0) && (private != 0)) {
+ cur = xmlSecAddChild(node, xmlSecNodeRSAPrivateExponent, xmlSecNs);
+ if(cur == NULL) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecAddChild",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAPrivateExponent));
+ goto done;
+ }
+ ret = xmlSecGCryptNodeSetSExpTokValue(cur, rsa, "d", 1);
+ if(ret < 0) {
+ xmlSecError(XMLSEC_ERRORS_HERE,
+ xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)),
+ "xmlSecGCryptNodeSetSExpTokValue",
+ XMLSEC_ERRORS_R_XMLSEC_FAILED,
+ "node=%s",
+ xmlSecErrorsSafeString(xmlSecNodeRSAPrivateExponent));
+ goto done;
+ }
+ }
+
+ /* success */
+ res = 0;
+
+done:
+ if(rsa != NULL) {
+ gcry_sexp_release(rsa);
+ }
+
+ return(res);
+}
+
+#endif /* XMLSEC_NO_RSA */