/**
 * XML Security Library (http://www.aleksey.com/xmlsec).
 *
 * This is free software; see the Copyright file in the source distribution for precise wording.
 *
 * Copyright (C) 2002-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
 */
/**
 * @addtogroup xmlsec_gnutls_crypto
 * @brief Signatures implementation for GnuTLS.
 */
#include "globals.h"

#include <string.h>

#include <gnutls/gnutls.h>
#include <gnutls/abstract.h>
#include <gnutls/crypto.h>

#include <xmlsec/xmlsec.h>
#include <xmlsec/keys.h>
#include <xmlsec/transforms.h>
#include <xmlsec/errors.h>

#include <xmlsec/gnutls/crypto.h>


#include "../cast_helpers.h"

/* https://www.w3.org/TR/xmldsig-core1/#sec-DSA
 * The output of the DSA algorithm consists of a pair of integers usually referred by the pair (r, s).
 * DSA-SHA1: Integer to octet-stream conversion must be done according to the I2OSP operation defined
 *           in the RFC 3447 [PKCS1] specification with a l parameter equal to 20
 * DSA-SHA256: The pairs (2048, 256) and (3072, 256) correspond to the algorithm DSAwithSHA256
 */
#define XMLSEC_GNUTLS_SIGNATURE_DSA_SHA1_HALF_LEN              20
#define XMLSEC_GNUTLS_SIGNATURE_DSA_SHA256_HALF_LEN            (256 / 8)

/******************************************************************************
 *
 * Internal GNUTLS signatures ctx
 *
  *****************************************************************************/
typedef gnutls_pubkey_t     (*xmlSecGnuTLSKeyDataGetPublicKeyMethod)      (xmlSecKeyDataPtr data);
typedef gnutls_privkey_t    (*xmlSecGnuTLSKeyDataGetPrivateKeyMethod)     (xmlSecKeyDataPtr data);


typedef struct _xmlSecGnuTLSSignatureCtx   xmlSecGnuTLSSignatureCtx,
                                          *xmlSecGnuTLSSignatureCtxPtr;
struct _xmlSecGnuTLSSignatureCtx {
    xmlSecGnuTLSKeyDataGetPublicKeyMethod   getPubKey;
    xmlSecGnuTLSKeyDataGetPrivateKeyMethod  getPrivKey;

    gnutls_digest_algorithm_t   dgstAlgo;
    gnutls_hash_hd_t            hash;

    /* either digest of content; or the content to be signed */
    xmlSecBuffer                preSignBuffer;

    xmlSecKeyDataId             keyId;
    xmlSecKeyDataPtr            keyData;
    gnutls_sign_algorithm_t     signAlgo;
    unsigned int                signFlags;
    unsigned int                verifyFlags;
};

/******************************************************************************
 *
 * Signature transforms
 *
  *****************************************************************************/
XMLSEC_TRANSFORM_DECLARE(GnuTLSSignature, xmlSecGnuTLSSignatureCtx)
#define xmlSecGnuTLSSignatureSize XMLSEC_TRANSFORM_SIZE(GnuTLSSignature)


static int      xmlSecGnuTLSSignatureCheckId                    (xmlSecTransformPtr transform);
static int      xmlSecGnuTLSSignatureInitialize                 (xmlSecTransformPtr transform);
static void     xmlSecGnuTLSSignatureFinalize                   (xmlSecTransformPtr transform);
static int      xmlSecGnuTLSSignatureSetKeyReq                  (xmlSecTransformPtr transform,
                                                                 xmlSecKeyReqPtr keyReq);
static int      xmlSecGnuTLSSignatureSetKey                     (xmlSecTransformPtr transform,
                                                                 xmlSecKeyPtr key);
static int      xmlSecGnuTLSSignatureVerify                     (xmlSecTransformPtr transform,
                                                                 const xmlSecByte* data,
                                                                 xmlSecSize dataSize,
                                                                 xmlSecTransformCtxPtr transformCtx);
static int      xmlSecGnuTLSSignatureExecute                    (xmlSecTransformPtr transform,
                                                                 int last,
                                                                 xmlSecTransformCtxPtr transformCtx);


static int
xmlSecGnuTLSSignatureCheckId(xmlSecTransformPtr transform) {
    /*  DSA */
#ifndef XMLSEC_NO_DSA

#ifndef XMLSEC_NO_SHA1
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformDsaSha1Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA1 */

#ifndef XMLSEC_NO_SHA256
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformDsaSha256Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA256 */

#endif /* XMLSEC_NO_DSA */

    /*  ECDSA */
#ifndef XMLSEC_NO_EC

#ifndef XMLSEC_NO_SHA1
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha1Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA1 */

#ifndef XMLSEC_NO_SHA224
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha224Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA224 */

#ifndef XMLSEC_NO_SHA256
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha256Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA256 */

#ifndef XMLSEC_NO_SHA384
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha384Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA384 */

#ifndef XMLSEC_NO_SHA512
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha512Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA512 */

#ifndef XMLSEC_NO_SHA3
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha3_224Id)) {
        return(1);
    }
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha3_256Id)) {
        return(1);
    }
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha3_384Id)) {
        return(1);
    }
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha3_512Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA3 */

#endif /* XMLSEC_NO_EC */

    /*  GOST 2001  */
#ifndef XMLSEC_NO_GOST
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformGost2001GostR3411_94Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_GOST */

#ifndef XMLSEC_NO_GOST2012
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformGostR3410_2012GostR3411_2012_256Id)) {
        return(1);
    }

    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformGostR3410_2012GostR3411_2012_512Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_GOST2012 */

    /*  ML-DSA  */
#ifndef XMLSEC_NO_MLDSA
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformMLDSA44Id)) {
        return(1);
    } else
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformMLDSA65Id)) {
        return(1);
    } else
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformMLDSA87Id)) {
        return(1);
    } else
#endif /* XMLSEC_NO_MLDSA */

    /*  EdDSA  */
#ifndef XMLSEC_NO_EDDSA
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEdDSAEd25519Id)) {
        return(1);
    } else
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEdDSAEd448Id)) {
        return(1);
    } else
#endif /* XMLSEC_NO_EDDSA */

    /*  RSA  */
#ifndef XMLSEC_NO_RSA

#ifndef XMLSEC_NO_SHA1
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaSha1Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA1 */

#ifndef XMLSEC_NO_SHA224
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaSha224Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA224 */

#ifndef XMLSEC_NO_SHA256
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaSha256Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA256 */

#ifndef XMLSEC_NO_SHA384
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaSha384Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA384 */

#ifndef XMLSEC_NO_SHA512
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaSha512Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA512 */

#ifndef XMLSEC_NO_SHA256
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaPssSha256Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA256 */

#ifndef XMLSEC_NO_SHA384
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaPssSha384Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA384 */

#ifndef XMLSEC_NO_SHA512
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaPssSha512Id)) {
        return(1);
    }
#endif /* XMLSEC_NO_SHA512 */

#endif /* XMLSEC_NO_RSA */

    return(0);
}

static int
xmlSecGnuTLSSignatureInitialize(xmlSecTransformPtr transform) {
    xmlSecGnuTLSSignatureCtxPtr ctx;
    int err;

    xmlSecAssert2(xmlSecGnuTLSSignatureCheckId(transform), -1);
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSSignatureSize), -1);
    ctx = xmlSecGnuTLSSignatureGetCtx(transform);
    xmlSecAssert2(ctx != NULL, -1);

    memset(ctx, 0, sizeof(xmlSecGnuTLSSignatureCtx));

    /*  DSA  */
#ifndef XMLSEC_NO_DSA

#ifndef XMLSEC_NO_SHA1
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformDsaSha1Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataDsaId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA1;
        ctx->signAlgo   = GNUTLS_SIGN_DSA_SHA1;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataDsaGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataDsaGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA1 */

#ifndef XMLSEC_NO_SHA256
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformDsaSha256Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataDsaId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA256;
        ctx->signAlgo   = GNUTLS_SIGN_DSA_SHA256;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataDsaGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataDsaGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA256 */

#endif /* XMLSEC_NO_DSA */

    /*  ECDSA */
#ifndef XMLSEC_NO_SHA1
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha1Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEcId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA1;
        ctx->signAlgo   = GNUTLS_SIGN_ECDSA_SHA1;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEcGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEcGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA1 */

#ifndef XMLSEC_NO_SHA224
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha224Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEcId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA224;
        ctx->signAlgo   = GNUTLS_SIGN_ECDSA_SHA224;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEcGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEcGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA224 */

#ifndef XMLSEC_NO_SHA256
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha256Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEcId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA256;
        ctx->signAlgo   = GNUTLS_SIGN_ECDSA_SHA256;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEcGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEcGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA256 */

#ifndef XMLSEC_NO_SHA384
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha384Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEcId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA384;
        ctx->signAlgo   = GNUTLS_SIGN_ECDSA_SHA384;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEcGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEcGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA384 */

#ifndef XMLSEC_NO_SHA512
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha512Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEcId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA512;
        ctx->signAlgo   = GNUTLS_SIGN_ECDSA_SHA512;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEcGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEcGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA512 */

    /*  ECDSA SHA3 */
#ifndef XMLSEC_NO_SHA3
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha3_224Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEcId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA3_224;
        ctx->signAlgo   = GNUTLS_SIGN_ECDSA_SHA3_224;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEcGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEcGetPrivateKey;
    } else
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha3_256Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEcId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA3_256;
        ctx->signAlgo   = GNUTLS_SIGN_ECDSA_SHA3_256;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEcGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEcGetPrivateKey;
    } else
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha3_384Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEcId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA3_384;
        ctx->signAlgo   = GNUTLS_SIGN_ECDSA_SHA3_384;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEcGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEcGetPrivateKey;
    } else
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEcdsaSha3_512Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEcId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA3_512;
        ctx->signAlgo   = GNUTLS_SIGN_ECDSA_SHA3_512;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEcGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEcGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA3 */

    /*  GOST 2001  */
#ifndef XMLSEC_NO_GOST
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformGost2001GostR3411_94Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataGost2001Id;
        ctx->dgstAlgo   = GNUTLS_DIG_GOSTR_94;
        ctx->signAlgo   = GNUTLS_SIGN_GOST_94;
        ctx->verifyFlags = GNUTLS_VERIFY_ALLOW_BROKEN;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataGost2001GetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataGost2001GetPrivateKey;
    } else
#endif /* XMLSEC_NO_GOST */

    /*  GOST 2012  */
#ifndef XMLSEC_NO_GOST2012
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformGostR3410_2012GostR3411_2012_256Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataGost2012_256Id;
        ctx->dgstAlgo   = GNUTLS_DIG_STREEBOG_256;
        ctx->signAlgo   = GNUTLS_SIGN_GOST_256;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataGost2012_256GetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataGost2012_256GetPrivateKey;
    } else

    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformGostR3410_2012GostR3411_2012_512Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataGost2012_512Id;
        ctx->dgstAlgo   = GNUTLS_DIG_STREEBOG_512;
        ctx->signAlgo   = GNUTLS_SIGN_GOST_512;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataGost2012_512GetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataGost2012_512GetPrivateKey;
    } else
#endif /* XMLSEC_NO_GOST2012 */

    /*  ML-DSA  */
#ifndef XMLSEC_NO_MLDSA
    /* ML-DSA uses hard coded SHAKE-128 and SHAKE-256 so no need to have digest here */
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformMLDSA44Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataMLDSAId;
        ctx->dgstAlgo   = GNUTLS_DIG_UNKNOWN;
        ctx->signAlgo   = GNUTLS_SIGN_MLDSA44;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataMLDSAGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataMLDSAGetPrivateKey;
    } else
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformMLDSA65Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataMLDSAId;
        ctx->dgstAlgo   = GNUTLS_DIG_UNKNOWN;
        ctx->signAlgo   = GNUTLS_SIGN_MLDSA65;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataMLDSAGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataMLDSAGetPrivateKey;
    } else
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformMLDSA87Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataMLDSAId;
        ctx->dgstAlgo   = GNUTLS_DIG_UNKNOWN;
        ctx->signAlgo   = GNUTLS_SIGN_MLDSA87;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataMLDSAGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataMLDSAGetPrivateKey;
    } else
#endif /* XMLSEC_NO_MLDSA */

    /*  EdDSA  */
#ifndef XMLSEC_NO_EDDSA
    /* EdDSA uses its own internally defined hash so no need to have digest here */
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEdDSAEd25519Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEdDSAId;
        ctx->dgstAlgo   = GNUTLS_DIG_UNKNOWN;
        ctx->signAlgo   = GNUTLS_SIGN_EDDSA_ED25519;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEdDSAGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEdDSAGetPrivateKey;
    } else
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformEdDSAEd448Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataEdDSAId;
        ctx->dgstAlgo   = GNUTLS_DIG_UNKNOWN;
        ctx->signAlgo   = GNUTLS_SIGN_EDDSA_ED448;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataEdDSAGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataEdDSAGetPrivateKey;
    } else
#endif /* XMLSEC_NO_EDDSA */

    /*  RSA  */
#ifndef XMLSEC_NO_RSA

#ifndef XMLSEC_NO_SHA1
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaSha1Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataRsaId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA1;
        ctx->signAlgo   = GNUTLS_SIGN_RSA_SHA1;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataRsaGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataRsaGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA1 */

#ifndef XMLSEC_NO_SHA224
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaSha224Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataRsaId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA224;
        ctx->signAlgo   = GNUTLS_SIGN_RSA_SHA224;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataRsaGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataRsaGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA224 */

#ifndef XMLSEC_NO_SHA256
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaSha256Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataRsaId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA256;
        ctx->signAlgo   = GNUTLS_SIGN_RSA_SHA256;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataRsaGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataRsaGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA256 */

#ifndef XMLSEC_NO_SHA384
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaSha384Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataRsaId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA384;
        ctx->signAlgo   = GNUTLS_SIGN_RSA_SHA384;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataRsaGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataRsaGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA384 */

#ifndef XMLSEC_NO_SHA512
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaSha512Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataRsaId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA512;
        ctx->signAlgo   = GNUTLS_SIGN_RSA_SHA512;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataRsaGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataRsaGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA512 */

#ifndef XMLSEC_NO_SHA256
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaPssSha256Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataRsaId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA256;
        ctx->signAlgo   = GNUTLS_SIGN_RSA_PSS_SHA256;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataRsaGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataRsaGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA256 */

#ifndef XMLSEC_NO_SHA384
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaPssSha384Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataRsaId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA384;
        ctx->signAlgo   = GNUTLS_SIGN_RSA_PSS_SHA384;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataRsaGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataRsaGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA384 */

#ifndef XMLSEC_NO_SHA512
    if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformRsaPssSha512Id)) {
        ctx->keyId      = xmlSecGnuTLSKeyDataRsaId;
        ctx->dgstAlgo   = GNUTLS_DIG_SHA512;
        ctx->signAlgo   = GNUTLS_SIGN_RSA_PSS_SHA512;
        ctx->getPubKey  = xmlSecGnuTLSKeyDataRsaGetPublicKey;
        ctx->getPrivKey = xmlSecGnuTLSKeyDataRsaGetPrivateKey;
    } else
#endif /* XMLSEC_NO_SHA512 */

#endif /* XMLSEC_NO_RSA */

    if(1) {
        xmlSecInvalidTransfromError(transform)
        return(-1);
    }

    /* create hash (skip for algorithms that don't use separate digest like ML-DSA) */
    if(ctx->dgstAlgo != GNUTLS_DIG_UNKNOWN) {
        err =  gnutls_hash_init(&(ctx->hash), ctx->dgstAlgo);
        if(err != GNUTLS_E_SUCCESS) {
            xmlSecGnuTLSError("gnutls_hash_init", err, NULL);
            return(-1);
        }
    }

    /* create buffer */
    if(xmlSecBufferInitialize(&(ctx->preSignBuffer), 0) < 0) {
        xmlSecInternalError("xmlSecBufferInitialize(preSignBuffer)", xmlSecTransformGetName(transform));
        return(-1);
    }

    /* done */
    return(0);
}

static void
xmlSecGnuTLSSignatureFinalize(xmlSecTransformPtr transform) {
    xmlSecGnuTLSSignatureCtxPtr ctx;

    xmlSecAssert(xmlSecGnuTLSSignatureCheckId(transform));
    xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecGnuTLSSignatureSize));
    xmlSecAssert((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify));

    ctx = xmlSecGnuTLSSignatureGetCtx(transform);
    xmlSecAssert(ctx != NULL);

    if(ctx->keyData != NULL) {
        xmlSecKeyDataDestroy(ctx->keyData);
    }
    if(ctx->hash != NULL) {
        gnutls_hash_deinit(ctx->hash, NULL);
    }
    xmlSecBufferFinalize(&(ctx->preSignBuffer));
    memset(ctx, 0, sizeof(xmlSecGnuTLSSignatureCtx));
}

static int
xmlSecGnuTLSSignatureSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) {
    xmlSecGnuTLSSignatureCtxPtr ctx;
    xmlSecKeyDataPtr value;

    xmlSecAssert2(xmlSecGnuTLSSignatureCheckId(transform), -1);
    xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1);
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSSignatureSize), -1);
    xmlSecAssert2(key != NULL, -1);

    ctx = xmlSecGnuTLSSignatureGetCtx(transform);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(ctx->keyId != NULL, -1);
    xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1);

    value = xmlSecKeyGetValue(key);
    xmlSecAssert2(value != NULL, -1);

    ctx->keyData = xmlSecKeyDataDuplicate(value);
    if(ctx->keyData == NULL) {
        xmlSecInternalError("xmlSecKeyDataDuplicate", xmlSecTransformGetName(transform));
        return(-1);
    }

    return(0);
}

static int
xmlSecGnuTLSSignatureSetKeyReq(xmlSecTransformPtr transform,  xmlSecKeyReqPtr keyReq) {
    xmlSecGnuTLSSignatureCtxPtr ctx;

    xmlSecAssert2(xmlSecGnuTLSSignatureCheckId(transform), -1);
    xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1);
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSSignatureSize), -1);
    xmlSecAssert2(keyReq != NULL, -1);

    ctx = xmlSecGnuTLSSignatureGetCtx(transform);
    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(ctx->keyId != NULL, -1);

    keyReq->keyId = ctx->keyId;
    if(transform->operation == xmlSecTransformOperationSign) {
        keyReq->keyType  = xmlSecKeyDataTypePrivate;
        keyReq->keyUsage = xmlSecKeyUsageSign;
    } else {
        keyReq->keyType  = xmlSecKeyDataTypePublic;
        keyReq->keyUsage = xmlSecKeyUsageVerify;
    }
    return(0);
}

/*
 * https://www.w3.org/TR/xmldsig-core1/#sec-DSA
 *
 * The output of the DSA algorithm consists of a pair of integers usually referred by the pair (r, s).
 * The signature value consists of the base64 encoding of the concatenation of two octet-streams that
 * respectively result from the octet-encoding of the values r and s in that order. Integer to octet-stream
 * conversion must be done according to the I2OSP operation defined in the RFC 3447 [PKCS1] specification
 * with a l parameter equal to 20.
 *
 * https://www.w3.org/TR/xmldsig-core1/#sec-ECDSA
 *
 * The output of the ECDSA algorithm consists of a pair of integers usually referred by the pair (r, s).
 * The signature value consists of the base64 encoding of the concatenation of two octet-streams that respectively
 * result from the octet-encoding of the values r and s in that order. Integer to octet-stream conversion must
 * be done according to the I2OSP operation defined in the RFC 3447 [PKCS1] specification with the l parameter equal
 * to the size of the base point order of the curve in bytes (e.g. 32 for the P-256 curve and 66 for the P-521 curve).
 *
 * DER DSA signature:
 *      SEQUENCE            30 <length byte>
 *      INTEGER (r)         02 <length byte> <integer bytes>
 *      INTEGER (s)         02 <length byte> <integer bytes>
 */

#define XMLSEC_GNUTLS_ASN1_TAG_SEQUENCE 0x30
#define XMLSEC_GNUTLS_ASN1_TAG_INTEGER  0x02

#define XMLSEC_GNUTLS_GET_SIZE_OF_SIZE(size, sizeOfSize) \
    if((size) <= 0x78) {                                 \
        (sizeOfSize) = 1;                                \
    } else if((size) <= 0xFF) {                          \
        (sizeOfSize) = 2;                                \
    } else if((size) <= 0xFFFF) {                        \
        (sizeOfSize) = 3;                                \
    } else {                                             \
        xmlSecInvalidSizeMoreThanError("ASN1 value length", (size), (xmlSecSize)(0xFFFF), NULL); \
        return(-1);                                      \
    }


#define XMLSEC_GNUTLS_PUT_LENGTH(pp, size)               \
    if((size) <= 0x78) {                                 \
        (*(pp)++) = (xmlSecByte)(size);                  \
    } else if((size) <= 0xFF) {                          \
        (*(pp)++) = (xmlSecByte)(0x81);                  \
        (*(pp)++) = (xmlSecByte)((size) & 0xFF);         \
    } else if((size) <= 0xFFFF) {                        \
        (*(pp)++) = (xmlSecByte)(0x82);                  \
        (*(pp)++) = (xmlSecByte)(((size) >> 8) & 0xFF);  \
        (*(pp)++) = (xmlSecByte)((size) & 0xFF);         \
    } else {                                             \
        xmlSecInvalidSizeMoreThanError("ASN1 value length", (size), (xmlSecSize)(0xFFFF), NULL); \
        return(-1);                                      \
    }

static int
xmlSecGnuTLSToDer(const gnutls_datum_t* src, gnutls_datum_t* dst, xmlSecSize size) {
    xmlSecByte * pp;
    xmlSecSize sizeOfSize;
    xmlSecSize seqSize, sizeOfSeqSize;
    xmlSecSize length;

    xmlSecAssert2(src != NULL, -1);
    xmlSecAssert2(src->data != NULL, -1);
    xmlSecAssert2(dst != NULL, -1);
    xmlSecAssert2(dst->data == NULL, -1);
    xmlSecAssert2(size > 0, -1);


    /* check size: we expect the r and s to be the same size and match the size of
     * the key (RFC 6931) */
    if(src->size == 2 * size) {
        /* good, do nothing */
    } else if((src->size < 2 * size) && (src->size % 2 == 0)) {
        /* however some implementations (e.g. Java) cut leading zeros:
         * https://github.com/lsh123/xmlsec/issues/228 */
        size = src->size / 2;
    } else if((src->size > 2 * size) && (src->size % 2 == 0)) {
        /* however some implementations (e.g. Java) add leading zeros:
         * https://github.com/lsh123/xmlsec/issues/941*/
        size = src->size / 2;
    } else {
        xmlSecInternalError3("Invalid signature size", NULL,
            "actual=%u; expected=" XMLSEC_SIZE_FMT, src->size, 2 * size);
        return(-1);
    }

    XMLSEC_GNUTLS_GET_SIZE_OF_SIZE(size, sizeOfSize);
    seqSize = 2 * (size + sizeOfSize + 1); /* 2 integers: 2 * (int tag + int len + int val)*/

    XMLSEC_GNUTLS_GET_SIZE_OF_SIZE(seqSize, sizeOfSeqSize);
    length = 1 + sizeOfSeqSize + seqSize; /* sequence: sqn tag + sqn len + sqn val */

    /* allocate memory */
    XMLSEC_SAFE_CAST_SIZE_TO_UINT(length, dst->size, return(-1), NULL);
    dst->data = gnutls_malloc(dst->size);
    if(dst->data == NULL) {
        xmlSecGnuTLSError("gnutls_malloc", 0, NULL);
        return(-1);
    }
    pp = dst->data;

    /* sequence */
    (*pp++) = XMLSEC_GNUTLS_ASN1_TAG_SEQUENCE;
    XMLSEC_GNUTLS_PUT_LENGTH(pp, seqSize);

    /* r */
    (*pp++) = XMLSEC_GNUTLS_ASN1_TAG_INTEGER;
    XMLSEC_GNUTLS_PUT_LENGTH(pp, size);
    memcpy(pp, src->data, size);
    pp += size;

    /* s */
    (*pp++) = XMLSEC_GNUTLS_ASN1_TAG_INTEGER;
    XMLSEC_GNUTLS_PUT_LENGTH(pp, size);
    memcpy(pp, src->data + size, size);
    pp += size;

    /* success */
    return(0);
}

#define XMLSEC_GNUTLS_GET_BYTE(data, dataSize, ii, cc)      \
    if((*(ii)) >= (dataSize)) {                             \
        return(-1);                                         \
    }                                                       \
    (cc) = (data)[(*(ii))++];                               \


static int
xmlSecGnuTLSReadDerLength(const xmlSecByte * data, xmlSecSize dataSize, xmlSecSize * ii, xmlSecSize * res) {
    xmlSecSize cc;

    xmlSecAssert2(data != NULL, -1);
    xmlSecAssert2(ii != NULL, -1);
    xmlSecAssert2(res != NULL, -1);

    XMLSEC_GNUTLS_GET_BYTE(data, dataSize, ii, cc);
    if((cc & 0x80) == 0) {
        (*res) = cc;
    } else if (cc == 0x80) {
        /* indefinite length not supported */
        return(-1);
    } else if (cc == 0xff) {
        /* forbidden length value.  */
        return(-1);
    } else {
        xmlSecSize length = 0;
        for(xmlSecSize count = cc & 0x7f; count; count--) {
            XMLSEC_GNUTLS_GET_BYTE(data, dataSize, ii, cc);
            length <<= 8;
            length |= (cc & 0xff);
        }
        (*res) = length;
    }

    /* success */
    return(0);
}

static int
xmlSecGnuTLSReadDerInteger(const xmlSecByte * data, xmlSecSize dataSize, xmlSecSize * ii, xmlSecByte * res, xmlSecSize resSize) {
    xmlSecSize cc;
    xmlSecSize len;
    int ret;

    xmlSecAssert2(data != NULL, -1);
    xmlSecAssert2(ii != NULL, -1);
    xmlSecAssert2(res != NULL, -1);

    /* tag */
    XMLSEC_GNUTLS_GET_BYTE(data, dataSize, ii, cc);
    if(cc != XMLSEC_GNUTLS_ASN1_TAG_INTEGER) {
        return(-1);
    }

    /* len */
    ret = xmlSecGnuTLSReadDerLength(data, dataSize, ii, &len);
    if(ret < 0) {
        return(-1);
    }

    /* val */
    if(dataSize < (*ii) + len) {
        return(-1);
    }
    /* skip zeros if any */
    while((len > 0) && (data[(*ii)] == 0)) {
        ++(*ii);
        --len;
    }
    if(len > resSize) {
        return(-1);
    }
    /* add 0s at the beginning if needed */
    memcpy(res + (resSize - len), data + (*ii), len);
    (*ii) += len;

    /* success */
    return(0);
}

static int
xmlSecGnuTLSFromDer(const gnutls_datum_t* src, gnutls_datum_t* dst, xmlSecSize size) {
    xmlSecSize ii = 0;
    xmlSecSize len, srcSize;
    int ret;
    int res = -1;

    xmlSecAssert2(src != NULL, -1);
    xmlSecAssert2(src->data != NULL, -1);
    xmlSecAssert2(dst != NULL, -1);
    xmlSecAssert2(dst->data == NULL, -1);
    xmlSecAssert2(size > 0, -1);

    /* allocate memory */
    len = 2 * size;
    XMLSEC_SAFE_CAST_SIZE_TO_UINT(len, dst->size, return(-1), NULL);
    dst->data = gnutls_malloc(dst->size);
    if(dst->data == NULL) {
        xmlSecGnuTLSError("gnutls_malloc", 0, NULL);
        return(-1);
    }
    memset(dst->data, 0, dst->size);

    XMLSEC_SAFE_CAST_UINT_TO_SIZE(src->size, srcSize, goto done, NULL);

    /* sequence tag */
    if(srcSize < ii + 1) {
        xmlSecInvalidSizeLessThanError("Expected asn1 sequence tag",
                    srcSize, ii + 2, NULL);
        goto done;
    }
    if(src->data[ii] != XMLSEC_GNUTLS_ASN1_TAG_SEQUENCE) {
        xmlSecInvalidDataError("Expected asn1 sequence tag", NULL);
        goto done;
    }
    ++ii;

    /* sequence len */
    ret = xmlSecGnuTLSReadDerLength(src->data, srcSize, &ii, &len);
    if(ret < 0) {
        xmlSecInvalidDataError("Invalid DER sequence length", NULL);
        goto done;
    }

    /* r */
    ret = xmlSecGnuTLSReadDerInteger(src->data, srcSize, &ii, dst->data, size);
    if(ret < 0) {
        xmlSecInvalidDataError("Cannot read DER integer r", NULL);
        goto done;
    }

    /* s */
    ret = xmlSecGnuTLSReadDerInteger(src->data, srcSize, &ii, dst->data + size, size);
    if(ret < 0) {
        xmlSecInvalidDataError("Cannot read DER integer s", NULL);
        goto done;
    }

    /* check leftovers */
    if(ii != srcSize) {
        xmlSecInvalidDataError("Unexpected data", NULL);
        goto done;
    }

    /* success */
    res = 0;

done:
    if(res < 0) {
        if(dst->data != NULL) {
            gnutls_free(dst->data);
            dst->data = NULL;
        }
        dst->size = 0;
    }
    return(res);
}

/* returns res = 0 if no der conversion is expected or the half size of the resulting signature
(i.e. size of each r and s integers)
*/
static int
xmlSecGnuTLSSignatureGetDerHalfSize(gnutls_sign_algorithm_t algo, xmlSecSize keySize, xmlSecSize * res) {
    xmlSecAssert2(res != 0, -1);

    switch(algo) {
        /*  Fixed length (DSA-SHA*)  */
#ifndef XMLSEC_NO_DSA
    case GNUTLS_SIGN_DSA_SHA1:
        (*res) = XMLSEC_GNUTLS_SIGNATURE_DSA_SHA1_HALF_LEN;
        break;
    case GNUTLS_SIGN_DSA_SHA256:
        (*res) = XMLSEC_GNUTLS_SIGNATURE_DSA_SHA256_HALF_LEN;
        break;
#endif /* XMLSEC_NO_DSA */

        /*  Key length (ECDSA-SHA*)  */
#ifndef XMLSEC_NO_EC
    case GNUTLS_SIGN_ECDSA_SHA1:
    case GNUTLS_SIGN_ECDSA_SHA224:
    case GNUTLS_SIGN_ECDSA_SHA256:
    case GNUTLS_SIGN_ECDSA_SHA384:
    case GNUTLS_SIGN_ECDSA_SHA512:
    case GNUTLS_SIGN_ECDSA_SHA3_224:
    case GNUTLS_SIGN_ECDSA_SHA3_256:
    case GNUTLS_SIGN_ECDSA_SHA3_384:
    case GNUTLS_SIGN_ECDSA_SHA3_512:
        if(keySize < 8) {
            xmlSecInvalidSizeDataError("keySize", keySize, "EC key size", NULL);
            return(-1);
        }
        (*res) = (keySize + 7) / 8;
        break;
#endif /* XMLSEC_NO_EC */

    default:
        /* don't convert to DER */
        (*res) = 0;
        break;
    }

    /* done */
    return(0);
}

static int
xmlSecGnuTLSSignatureGetDataToSign(xmlSecGnuTLSSignatureCtxPtr ctx, gnutls_datum_t* dataToSign)
{
    int ret;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(dataToSign != NULL, -1);

    if (ctx->hash != NULL) {
        unsigned int hashSize;

        /* get hash size and setup buffer */
        hashSize = gnutls_hash_get_len(ctx->dgstAlgo);
        if(hashSize <= 0) {
            xmlSecInternalError("gnutls_hash_get_len", NULL);
            return(-1);
        }

        ret = xmlSecBufferSetSize(&(ctx->preSignBuffer), hashSize);
        if(ret < 0) {
            xmlSecInternalError("xmlSecBufferSetSize", NULL);
            return(-1);
        }

        /* get hash */
        gnutls_hash_output(ctx->hash, xmlSecBufferGetData(&(ctx->preSignBuffer)));
        dataToSign->data = xmlSecBufferGetData(&(ctx->preSignBuffer));
        dataToSign->size = hashSize;
    } else {
        xmlSecSize dataSize;

        /* get data size -- we should have SOME data and zero size is an error */
        dataSize = xmlSecBufferGetSize(&(ctx->preSignBuffer));
        if(dataSize <= 0) {
            xmlSecInternalError("xmlSecBufferGetSize", NULL);
            return(-1);
        }

        /* no hash, sign the whole data */
        dataToSign->data = xmlSecBufferGetData(&(ctx->preSignBuffer));
        XMLSEC_SAFE_CAST_SIZE_TO_UINT(dataSize, dataToSign->size, return(-1), NULL);
   }

    /* done */
    return(0);
}

static int
xmlSecGnuTLSSignatureVerify(
    xmlSecTransformPtr transform,
    const xmlSecByte* data,
    xmlSecSize dataSize,
    xmlSecTransformCtxPtr transformCtx
) {
    xmlSecGnuTLSSignatureCtxPtr ctx;
    gnutls_datum_t dataToSign, signature;
    gnutls_pubkey_t pubkey;
    xmlSecSize keySize, signHalfSize = 0;
    int err;
    int ret;

    xmlSecAssert2(xmlSecGnuTLSSignatureCheckId(transform), -1);
    xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1);
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSSignatureSize), -1);
    xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1);
    xmlSecAssert2(data != NULL, -1);
    xmlSecAssert2(transformCtx != NULL, -1);

    ctx = xmlSecGnuTLSSignatureGetCtx(transform);
    xmlSecAssert2(ctx->keyData != NULL, -1);
    xmlSecAssert2(ctx->getPubKey != NULL, -1);

    /* get pubkey */
    pubkey = ctx->getPubKey(ctx->keyData);
    if(pubkey == NULL) {
        xmlSecInternalError("ctx->getPubKey", xmlSecTransformGetName(transform));
        return(-1);
    }

    /* do we need to convert signature to DER? */
    keySize = xmlSecKeyDataGetSize(ctx->keyData);
    if(keySize <= 0) {
        xmlSecInternalError("keySize", xmlSecTransformGetName(transform));
        return(-1);
    }
    ret = xmlSecGnuTLSSignatureGetDerHalfSize(ctx->signAlgo, keySize, &signHalfSize);
    if(ret < 0) {
        xmlSecInternalError("xmlSecGnuTLSSignatureGetDerHalfSize", xmlSecTransformGetName(transform));
        return(-1);
    }

    /* get data to sign */
    ret = xmlSecGnuTLSSignatureGetDataToSign(ctx, &dataToSign);
    if(ret < 0) {
        xmlSecInternalError("xmlSecGnuTLSSignatureGetDataToSign", xmlSecTransformGetName(transform));
        return(-1);
    }

    /* verify */
    signature.data = (xmlSecByte*)data;
    XMLSEC_SAFE_CAST_SIZE_TO_UINT(dataSize, signature.size, return(-1), xmlSecTransformGetName(transform));

    /* however some implementations (e.g. Java) just put ASN1 structure in the signature
     * and in this case we ALREADY have ASN1
     * https://github.com/lsh123/xmlsec/issues/995 */
    if((signHalfSize > 0) && ((transformCtx->flags & XMLSEC_TRANSFORMCTX_FLAGS_SUPPORT_ASN1_SIGNATURE_VALUES) == 0)) {
        gnutls_datum_t der_signature = { NULL, 0 };

        ret = xmlSecGnuTLSToDer(&signature, &der_signature, signHalfSize);
        if((ret < 0) || (der_signature.data == NULL)) {
            xmlSecInternalError("xmlSecGnuTLSToDer", xmlSecTransformGetName(transform));
            return(-1);
        }

        if(ctx->hash != NULL) {
            err = gnutls_pubkey_verify_hash2(pubkey, ctx->signAlgo, ctx->verifyFlags, &dataToSign, &der_signature);
        } else {
            err = gnutls_pubkey_verify_data2(pubkey, ctx->signAlgo, ctx->verifyFlags, &dataToSign, &der_signature);
        }
        gnutls_free(der_signature.data);
    } else {
        if(ctx->hash != NULL) {
            err = gnutls_pubkey_verify_hash2(pubkey, ctx->signAlgo, ctx->verifyFlags, &dataToSign, &signature);
        } else {
            err = gnutls_pubkey_verify_data2(pubkey, ctx->signAlgo, ctx->verifyFlags, &dataToSign, &signature);
        }
    }

    /* In case of a verification failure GNUTLS_E_PK_SIG_VERIFY_FAILED
       is returned, and zero or positive code on success. */
    if(err >= 0) {
        /* signature is good */
        transform->status = xmlSecTransformStatusOk;
    } else if(err == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
        /* signature verification failed */
        xmlSecOtherError(XMLSEC_ERRORS_R_DATA_NOT_MATCH, xmlSecTransformGetName(transform),
            "Signature verification failed");
        transform->status = xmlSecTransformStatusFail;
    } else {
        /* an error */
        if(ctx->hash != NULL) {
            xmlSecGnuTLSError("gnutls_pubkey_verify_hash2", err, xmlSecTransformGetName(transform));
        } else {
            xmlSecGnuTLSError("gnutls_pubkey_verify_data2", err, xmlSecTransformGetName(transform));
        }
        return(-1);
    }

    /* done */
    return(0);
}

static int
xmlSecGnuTLSSignatureSign(
    xmlSecTransformPtr transform,
    xmlSecGnuTLSSignatureCtxPtr ctx,
    xmlSecBufferPtr out,
    xmlSecTransformCtxPtr transformCtx
) {
    gnutls_datum_t dataToSign, signature = { NULL, 0 };
    gnutls_privkey_t privkey;
    xmlSecSize keySize, signHalfSize = 0;
    int err;
    int ret;

    xmlSecAssert2(ctx != NULL, -1);
    xmlSecAssert2(ctx->keyData != NULL, -1);
    xmlSecAssert2(ctx->getPrivKey != NULL, -1);
    xmlSecAssert2(out != NULL, -1);
    xmlSecAssert2(transformCtx != NULL, -1);

    /* get key */
    privkey = ctx->getPrivKey(ctx->keyData);
    if(privkey == NULL) {
        xmlSecInternalError("ctx->getPrivKey", xmlSecTransformGetName(transform));
        return(-1);
    }

    /* do we need to convert signature from DER? */
    keySize = xmlSecKeyDataGetSize(ctx->keyData);
    if(keySize <= 0) {
        xmlSecInternalError("keySize", xmlSecTransformGetName(transform));
        return(-1);
    }
    ret = xmlSecGnuTLSSignatureGetDerHalfSize(ctx->signAlgo, keySize, &signHalfSize);
    if(ret < 0) {
        xmlSecInternalError("xmlSecGnuTLSSignatureGetDerHalfSize", xmlSecTransformGetName(transform));
        return(-1);
    }

    /* get data to sign */
    ret = xmlSecGnuTLSSignatureGetDataToSign(ctx, &dataToSign);
    if(ret < 0) {
        xmlSecInternalError("xmlSecGnuTLSSignatureGetDataToSign", xmlSecTransformGetName(transform));
        return(-1);
    }

    /* sign */
    if(ctx->hash != NULL) {
        err = gnutls_privkey_sign_hash2(privkey, ctx->signAlgo, ctx->signFlags, &dataToSign, &signature);
        if((err != GNUTLS_E_SUCCESS) || (signature.data == NULL)) {
            xmlSecGnuTLSError("gnutls_privkey_sign_hash2", err, xmlSecTransformGetName(transform));
            return(-1);
        }
    } else {
        err = gnutls_privkey_sign_data2(privkey, ctx->signAlgo, ctx->signFlags, &dataToSign, &signature);
        if((err != GNUTLS_E_SUCCESS) || (signature.data == NULL)) {
            xmlSecGnuTLSError("gnutls_privkey_sign_data2", err, xmlSecTransformGetName(transform));
            return(-1);
        }
    }

    /* however some implementations (e.g. Java) just put ASN1 structure in the signature
     * and in this case we ALREADY have ASN1
     * https://github.com/lsh123/xmlsec/issues/995 */
    if((signHalfSize > 0) && ((transformCtx->flags & XMLSEC_TRANSFORMCTX_FLAGS_SUPPORT_ASN1_SIGNATURE_VALUES) == 0)) {
        gnutls_datum_t xmldsig_signature = { NULL, 0 };

        ret = xmlSecGnuTLSFromDer(&signature, &xmldsig_signature, signHalfSize);
        if((ret < 0) || (xmldsig_signature.data == NULL)) {
            xmlSecInternalError("xmlSecGnuTLSFromDer", xmlSecTransformGetName(transform));
            gnutls_free(signature.data);
            return(-1);
        }

        /* xmldsig_signature -> signature */
        gnutls_free(signature.data);
        signature.data = xmldsig_signature.data;
        signature.size = xmldsig_signature.size;
    }

    /* append to the output */
    ret = xmlSecBufferAppend(out, signature.data, signature.size);
    if(ret < 0) {
        xmlSecInternalError("xmlSecBufferAppend", xmlSecTransformGetName(transform));
        gnutls_free(signature.data);
        return(-1);
    }
    gnutls_free(signature.data);

    /* success */
    return(0);
}

static int
xmlSecGnuTLSSignatureExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) {
    xmlSecGnuTLSSignatureCtxPtr ctx;
    xmlSecBufferPtr in, out;
    xmlSecSize inSize, outSize;
    int err;
    int ret;

    xmlSecAssert2(xmlSecGnuTLSSignatureCheckId(transform), -1);
    xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1);
    xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSSignatureSize), -1);
    xmlSecAssert2(transformCtx != NULL, -1);

    ctx = xmlSecGnuTLSSignatureGetCtx(transform);
    xmlSecAssert2(ctx != NULL, -1);

    in = &(transform->inBuf);
    out = &(transform->outBuf);
    inSize = xmlSecBufferGetSize(in);
    outSize = xmlSecBufferGetSize(out);

    ctx = xmlSecGnuTLSSignatureGetCtx(transform);
    xmlSecAssert2(ctx != NULL, -1);

    if(transform->status == xmlSecTransformStatusNone) {
        xmlSecAssert2(outSize == 0, -1);
        transform->status = xmlSecTransformStatusWorking;
    }

    if((transform->status == xmlSecTransformStatusWorking) && (inSize > 0)) {
        /* update hash or buffer */
        if(ctx->hash != NULL) {
            err = gnutls_hash(ctx->hash, xmlSecBufferGetData(in), inSize);
            if(err != GNUTLS_E_SUCCESS) {
                xmlSecGnuTLSError("gnutls_hash", err, xmlSecTransformGetName(transform));
                return(-1);
            }
        } else {
            ret = xmlSecBufferAppend(&(ctx->preSignBuffer), xmlSecBufferGetData(in), inSize);
            if(ret < 0) {
                xmlSecInternalError("xmlSecBufferAppend(preSignBuffer)", xmlSecTransformGetName(transform));
                return(-1);
            }
        }

        /* remove input */
        ret = xmlSecBufferRemoveHead(in, inSize);
        if(ret < 0) {
            xmlSecInternalError2("xmlSecBufferRemoveHead", xmlSecTransformGetName(transform),
                "size=" XMLSEC_SIZE_FMT, inSize);
            return(-1);
        }
        inSize = 0;
    }

    if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) {
        xmlSecAssert2(outSize == 0, -1);
        if(transform->operation == xmlSecTransformOperationSign) {
            ret = xmlSecGnuTLSSignatureSign(transform, ctx, out, transformCtx);
            if(ret < 0) {
                xmlSecInternalError("xmlSecGnuTLSSignatureSign", xmlSecTransformGetName(transform));
                return(-1);
            }
        }
        transform->status = xmlSecTransformStatusFinished;
    }

    if((transform->status == xmlSecTransformStatusWorking) || (transform->status == xmlSecTransformStatusFinished)) {
        /* the only way we can get here is if there is no input */
        xmlSecAssert2(xmlSecBufferGetSize(&(transform->inBuf)) == 0, -1);
    } else {
        xmlSecInvalidTransfromStatusError(transform);
        return(-1);
    }

    return(0);
}


/* Helper macros to define the transform klass */

#define XMLSEC_GNUTLS_SIGNATURE_KLASS_EX(name, readNode)                                                \
static xmlSecTransformKlass xmlSecGnuTLS ## name ## Klass = {                                           \
    sizeof(xmlSecTransformKlass),               /* xmlSecSize klassSize */                              \
    xmlSecGnuTLSSignatureSize,                  /* xmlSecSize objSize */                                \
    xmlSecName ## name,                         /* const xmlChar* name; */                              \
    xmlSecHref ## name,                         /* const xmlChar* href; */                              \
    xmlSecTransformUsageSignatureMethod,        /* xmlSecTransformUsage usage; */                       \
    xmlSecGnuTLSSignatureInitialize,            /* xmlSecTransformInitializeMethod initialize; */       \
    xmlSecGnuTLSSignatureFinalize,              /* xmlSecTransformFinalizeMethod finalize; */           \
    readNode,                                   /* xmlSecTransformNodeReadMethod readNode; */           \
    NULL,                                       /* xmlSecTransformNodeWriteMethod writeNode; */         \
    xmlSecGnuTLSSignatureSetKeyReq,             /* xmlSecTransformSetKeyReqMethod setKeyReq; */         \
    xmlSecGnuTLSSignatureSetKey,                /* xmlSecTransformSetKeyMethod setKey; */               \
    xmlSecGnuTLSSignatureVerify,                /* xmlSecTransformVerifyMethod verify; */               \
    xmlSecTransformDefaultGetDataType,          /* xmlSecTransformGetDataTypeMethod getDataType; */     \
    xmlSecTransformDefaultPushBin,              /* xmlSecTransformPushBinMethod pushBin; */             \
    xmlSecTransformDefaultPopBin,               /* xmlSecTransformPopBinMethod popBin; */               \
    NULL,                                       /* xmlSecTransformPushXmlMethod pushXml; */             \
    NULL,                                       /* xmlSecTransformPopXmlMethod popXml; */               \
    xmlSecGnuTLSSignatureExecute,               /* xmlSecTransformExecuteMethod execute; */             \
    NULL,                                       /* void* reserved0; */                                  \
    NULL,                                       /* void* reserved1; */                                  \
};

#define XMLSEC_GNUTLS_SIGNATURE_KLASS(name)                                                             \
    XMLSEC_GNUTLS_SIGNATURE_KLASS_EX(name, NULL)


/*  DSA  */
#ifndef XMLSEC_NO_DSA

#ifndef XMLSEC_NO_SHA1
/******************************************************************************
 *
 * DSA-SHA1 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(DsaSha1)

/**
 * @brief The DSA-SHA1 signature transform klass.
 * @return DSA-SHA1 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformDsaSha1GetKlass(void) {
    return(&xmlSecGnuTLSDsaSha1Klass);
}
#endif /* XMLSEC_NO_SHA1 */


#ifndef XMLSEC_NO_SHA256
/******************************************************************************
 *
 * DSA-SHA2-256 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(DsaSha256)

/**
 * @brief The DSA-SHA2-256 signature transform klass.
 * @return DSA-SHA2-256 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformDsaSha256GetKlass(void) {
    return(&xmlSecGnuTLSDsaSha256Klass);
}
#endif /* XMLSEC_NO_SHA256 */

#endif /* XMLSEC_NO_DSA */

/*  EC */
#ifndef XMLSEC_NO_EC
/*
 * https://www.w3.org/TR/xmldsig-core1/#sec-ECDSA
 *
 * The output of the ECDSA algorithm consists of a pair of integers usually referred by the pair (r, s).
 * The signature value consists of the base64 encoding of the concatenation of two octet-streams that respectively
 * result from the octet-encoding of the values r and s in that order. Integer to octet-stream conversion must
 * be done according to the I2OSP operation defined in the RFC 3447 [PKCS1] specification with the l parameter equal
 * to the size of the base point order of the curve in bytes (e.g. 32 for the P-256 curve and 66 for the P-521 curve).
 */

#ifndef XMLSEC_NO_SHA1
/******************************************************************************
 *
 * ECDSA-SHA1 signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(EcdsaSha1)

/**
 * @brief The ECDSA-SHA1 signature transform klass.
 * @return ECDSA-SHA1 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEcdsaSha1GetKlass(void) {
    return(&xmlSecGnuTLSEcdsaSha1Klass);
}

#endif /* XMLSEC_NO_SHA1 */


#ifndef XMLSEC_NO_SHA224
/******************************************************************************
 *
 * ECDSA-SHA2-224 signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(EcdsaSha224)

/**
 * @brief The ECDSA-SHA2-224 signature transform klass.
 * @return ECDSA-SHA2-224 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEcdsaSha224GetKlass(void) {
    return(&xmlSecGnuTLSEcdsaSha224Klass);
}

#endif /* XMLSEC_NO_SHA224 */


#ifndef XMLSEC_NO_SHA256
/******************************************************************************
 *
 * ECDSA-SHA2-256 signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(EcdsaSha256)

/**
 * @brief The ECDSA-SHA2-256 signature transform klass.
 * @return ECDSA-SHA2-256 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEcdsaSha256GetKlass(void) {
    return(&xmlSecGnuTLSEcdsaSha256Klass);
}

#endif /* XMLSEC_NO_SHA256 */

#ifndef XMLSEC_NO_SHA384
/******************************************************************************
 *
 * ECDSA-SHA2-384 signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(EcdsaSha384)

/**
 * @brief The ECDSA-SHA2-384 signature transform klass.
 * @return ECDSA-SHA2-384 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEcdsaSha384GetKlass(void) {
    return(&xmlSecGnuTLSEcdsaSha384Klass);
}

#endif /* XMLSEC_NO_SHA384 */

#ifndef XMLSEC_NO_SHA512
/******************************************************************************
 *
 * ECDSA-SHA2-512 signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(EcdsaSha512)

/**
 * @brief The ECDSA-SHA2-512 signature transform klass.
 * @return ECDSA-SHA2-512 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEcdsaSha512GetKlass(void) {
    return(&xmlSecGnuTLSEcdsaSha512Klass);
}

#endif /* XMLSEC_NO_SHA512 */



#ifndef XMLSEC_NO_SHA3
/******************************************************************************
 *
 * ECDSA-SHA3-224 signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(EcdsaSha3_224)

/**
 * @brief The ECDSA-SHA3-224 signature transform klass.
 * @return ECDSA-SHA3-224 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEcdsaSha3_224GetKlass(void) {
    return(&xmlSecGnuTLSEcdsaSha3_224Klass);
}

/******************************************************************************
 *
 * ECDSA-SHA3-256 signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(EcdsaSha3_256)

/**
 * @brief The ECDSA-SHA3-256 signature transform klass.
 * @return ECDSA-SHA3-256 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEcdsaSha3_256GetKlass(void) {
    return(&xmlSecGnuTLSEcdsaSha3_256Klass);
}

/******************************************************************************
 *
 * ECDSA-SHA3-384 signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(EcdsaSha3_384)

/**
 * @brief The ECDSA-SHA3-384 signature transform klass.
 * @return ECDSA-SHA3-384 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEcdsaSha3_384GetKlass(void) {
    return(&xmlSecGnuTLSEcdsaSha3_384Klass);
}

/******************************************************************************
 *
 * ECDSA-SHA3-512 signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(EcdsaSha3_512)

/**
 * @brief The ECDSA-SHA3-512 signature transform klass.
 * @return ECDSA-SHA3-512 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEcdsaSha3_512GetKlass(void) {
    return(&xmlSecGnuTLSEcdsaSha3_512Klass);
}

#endif /* XMLSEC_NO_SHA3 */

#endif /* XMLSEC_NO_EC */


/*  GOST 2001  */
#ifndef XMLSEC_NO_GOST

/******************************************************************************
 *
 * GOST2001 GOSTR3411_94 signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(Gost2001GostR3411_94)

/**
 * @brief GOST2001 GOSTR3411_94 signature transform klass.
 * @details The GOST2001 GOSTR3411_94 signature transform klass.
 * @return GOST2001 GOSTR3411_94 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformGost2001GostR3411_94GetKlass(void) {
    return(&xmlSecGnuTLSGost2001GostR3411_94Klass);
}

#endif /* XMLSEC_NO_GOST */


/*  GOST 2012  */
#ifndef XMLSEC_NO_GOST2012

/******************************************************************************
 *
 * GOST R 34.10-2012 - GOST R 34.11-2012 256 bit signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(GostR3410_2012GostR3411_2012_256)

/**
 * @brief GOST R 34.10-2012 signature klass (256 bit).
 * @details The GOST R 34.10-2012 - GOST R 34.11-2012 256 bit signature transform klass.
 * @return GOST R 34.10-2012 - GOST R 34.11-2012 256 bit signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformGostR3410_2012GostR3411_2012_256GetKlass(void) {
    return(&xmlSecGnuTLSGostR3410_2012GostR3411_2012_256Klass);
}

/******************************************************************************
 *
 * GOST R 34.10-2012 - GOST R 34.11-2012 512 bit signature transform
 *
  *****************************************************************************/
XMLSEC_GNUTLS_SIGNATURE_KLASS(GostR3410_2012GostR3411_2012_512)

/**
 * @brief GOST R 34.10-2012 signature klass (512 bit).
 * @details The GOST R 34.10-2012 - GOST R 34.11-2012 512 bit signature transform klass.
 * @return GOST R 34.10-2012 - GOST R 34.11-2012 512 bit signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformGostR3410_2012GostR3411_2012_512GetKlass(void) {
    return(&xmlSecGnuTLSGostR3410_2012GostR3411_2012_512Klass);
}


#endif /* XMLSEC_NO_GOST2012 */


/*  RSA  */

#ifndef XMLSEC_NO_RSA

#ifndef XMLSEC_NO_SHA1
/******************************************************************************
 *
 * RSA-SHA1 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(RsaSha1)

/**
 * @brief The RSA-SHA1 signature transform klass.
 * @return RSA-SHA1 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformRsaSha1GetKlass(void) {
    return(&xmlSecGnuTLSRsaSha1Klass);
}
#endif /* XMLSEC_NO_SHA1 */

#ifndef XMLSEC_NO_SHA224
/******************************************************************************
 *
 * RSA-SHA2-224 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(RsaSha224)

/**
 * @brief The RSA-SHA2-224 signature transform klass.
 * @return RSA-SHA2-224 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformRsaSha224GetKlass(void) {
    return(&xmlSecGnuTLSRsaSha224Klass);
}
#endif /* XMLSEC_NO_SHA224 */

#ifndef XMLSEC_NO_SHA256
/******************************************************************************
 *
 * RSA-SHA2-256 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(RsaSha256)

/**
 * @brief The RSA-SHA2-256 signature transform klass.
 * @return RSA-SHA2-256 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformRsaSha256GetKlass(void) {
    return(&xmlSecGnuTLSRsaSha256Klass);
}
#endif /* XMLSEC_NO_SHA256 */


#ifndef XMLSEC_NO_SHA384
/******************************************************************************
 *
 * RSA-SHA2-384 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(RsaSha384)

/**
 * @brief The RSA-SHA2-384 signature transform klass.
 * @return RSA-SHA2-384 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformRsaSha384GetKlass(void) {
    return(&xmlSecGnuTLSRsaSha384Klass);
}
#endif /* XMLSEC_NO_SHA384 */


#ifndef XMLSEC_NO_SHA512
/******************************************************************************
 *
 * RSA-SHA2-512 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(RsaSha512)

/**
 * @brief The RSA-SHA2-512 signature transform klass.
 * @return RSA-SHA2-512 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformRsaSha512GetKlass(void) {
    return(&xmlSecGnuTLSRsaSha512Klass);
}
#endif /* XMLSEC_NO_SHA512 */



#ifndef XMLSEC_NO_SHA256
/******************************************************************************
 *
 * RSA-PSS-SHA2-256 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(RsaPssSha256)

/**
 * @brief The RSA-PSS-SHA2-256 signature transform klass.
 * @return RSA-PSS-SHA2-256 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformRsaPssSha256GetKlass(void) {
    return(&xmlSecGnuTLSRsaPssSha256Klass);
}
#endif /* XMLSEC_NO_SHA256 */


#ifndef XMLSEC_NO_SHA384
/******************************************************************************
 *
 * RSA-PSS-SHA2-384 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(RsaPssSha384)

/**
 * @brief The RSA-PSS-SHA2-384 signature transform klass.
 * @return RSA-PSS-SHA2-384 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformRsaPssSha384GetKlass(void) {
    return(&xmlSecGnuTLSRsaPssSha384Klass);
}
#endif /* XMLSEC_NO_SHA384 */


#ifndef XMLSEC_NO_SHA512
/******************************************************************************
 *
 * RSA-PSS-SHA2-512 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(RsaPssSha512)

/**
 * @brief The RSA-PSS-SHA2-512 signature transform klass.
 * @return RSA-PSS-SHA2-512 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformRsaPssSha512GetKlass(void) {
    return(&xmlSecGnuTLSRsaPssSha512Klass);
}
#endif /* XMLSEC_NO_SHA512 */

#endif /* XMLSEC_NO_RSA */


/******************************************************************************
 *
 * ML-DSA signatures
 *
  *****************************************************************************/
#ifndef XMLSEC_NO_MLDSA

/******************************************************************************
 *
 * ML-DSA-44 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(MLDSA44)

/**
 * @brief The ML-DSA-44 signature transform klass.
 * @return ML-DSA-44 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformMLDSA44GetKlass(void) {
    return(&xmlSecGnuTLSMLDSA44Klass);
}


/******************************************************************************
 *
 * ML-DSA-65 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(MLDSA65)

/**
 * @brief The ML-DSA-65 signature transform klass.
 * @return ML-DSA-65 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformMLDSA65GetKlass(void) {
    return(&xmlSecGnuTLSMLDSA65Klass);
}


/******************************************************************************
 *
 * ML-DSA-87 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(MLDSA87)

/**
 * @brief The ML-DSA-87 signature transform klass.
 * @return ML-DSA-87 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformMLDSA87GetKlass(void) {
    return(&xmlSecGnuTLSMLDSA87Klass);
}

#endif /* XMLSEC_NO_MLDSA */


/******************************************************************************
 *
 * EdDSA signatures
 *
  *****************************************************************************/
#ifndef XMLSEC_NO_EDDSA

/******************************************************************************
 *
 * EdDSA-Ed25519 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(EdDSAEd25519)

/**
 * @brief The EdDSA-Ed25519 signature transform klass.
 * @return EdDSA-Ed25519 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEdDSAEd25519GetKlass(void) {
    return(&xmlSecGnuTLSEdDSAEd25519Klass);
}


/******************************************************************************
 *
 * EdDSA-Ed448 signature transform
 *
  *****************************************************************************/

XMLSEC_GNUTLS_SIGNATURE_KLASS(EdDSAEd448)

/**
 * @brief The EdDSA-Ed448 signature transform klass.
 * @return EdDSA-Ed448 signature transform klass.
 */
xmlSecTransformId
xmlSecGnuTLSTransformEdDSAEd448GetKlass(void) {
    return(&xmlSecGnuTLSEdDSAEd448Klass);
}

#endif /* XMLSEC_NO_EDDSA */
