/
githubmirror
/
xmlsec
Обзор
Документация
Войти
/
githubmirror
/
xmlsec
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/openssl/signatures_legacy.c
1 118 строк
38 KB
lsh123
Update file headers for doxygen, use common copyright header, bump copyright to 2026 (#1122)
07 апр 2026, 04:13
Не верифицирован
07 апр 2026, 04:13
2e557ee
Код
Авторство
О чём код?
/** * 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_openssl_crypto * @brief Legacy signatures implementation for OpenSSL. */ /* * The ECDSA signature were added to EVP interface in 3.0.0 * https://www.openssl.org/docs/manmaster/man7/EVP_SIGNATURE-ECDSA.html * * OpenSSL 3.x implementation is in src/openssl/signatures.c */ #include "globals.h" #include <string.h> #include <openssl/evp.h> #include <openssl/rand.h> #include <openssl/sha.h> #include <openssl/bn.h> #include <xmlsec/xmlsec.h> #include <xmlsec/keys.h> #include <xmlsec/transforms.h> #include <xmlsec/errors.h> #include <xmlsec/openssl/crypto.h> #include <xmlsec/openssl/evp.h> #include "openssl_compat.h" #include "../cast_helpers.h" #if !defined(XMLSEC_OPENSSL_API_300) && !defined(XMLSEC_NO_EC) /****************************************************************************** * * Internal OpenSSL signatures ctx: forward declarations * *****************************************************************************/ typedef struct _xmlSecOpenSSLSignatureLegacyCtx xmlSecOpenSSLSignatureLegacyCtx, *xmlSecOpenSSLSignatureLegacyCtxPtr; static int xmlSecOpenSSLSignatureLegacyEcdsaSign (xmlSecOpenSSLSignatureLegacyCtxPtr ctx, xmlSecTransformCtxPtr transformCtx, xmlSecBufferPtr out); static int xmlSecOpenSSLSignatureLegacyEcdsaVerify (xmlSecOpenSSLSignatureLegacyCtxPtr ctx, xmlSecTransformCtxPtr transformCtx, const xmlSecByte* signData, xmlSecSize signSize); /****************************************************************************** * * Sign/verify callbacks * *****************************************************************************/ typedef int (*xmlSecOpenSSLSignatureLegacySignCallback) (xmlSecOpenSSLSignatureLegacyCtxPtr ctx, xmlSecTransformCtxPtr transformCtx, xmlSecBufferPtr out); typedef int (*xmlSecOpenSSLSignatureLegacyVerifyCallback) (xmlSecOpenSSLSignatureLegacyCtxPtr ctx, xmlSecTransformCtxPtr transformCtx, const xmlSecByte* signData, xmlSecSize signSize); /****************************************************************************** * * Internal OpenSSL signatures ctx * *****************************************************************************/ struct _xmlSecOpenSSLSignatureLegacyCtx { const EVP_MD* digest; EVP_MD_CTX* digestCtx; xmlSecKeyDataId keyId; xmlSecOpenSSLSignatureLegacySignCallback signCallback; xmlSecOpenSSLSignatureLegacyVerifyCallback verifyCallback; EVP_PKEY* pKey; unsigned char dgst[EVP_MAX_MD_SIZE]; unsigned int dgstSize; }; /****************************************************************************** * * Signature transforms * *****************************************************************************/ XMLSEC_TRANSFORM_DECLARE(OpenSSLSignatureLegacy, xmlSecOpenSSLSignatureLegacyCtx) #define xmlSecOpenSSLSignatureLegacySize XMLSEC_TRANSFORM_SIZE(OpenSSLSignatureLegacy) static int xmlSecOpenSSLSignatureLegacyCheckId (xmlSecTransformPtr transform); static int xmlSecOpenSSLSignatureLegacyInitialize (xmlSecTransformPtr transform); static void xmlSecOpenSSLSignatureLegacyFinalize (xmlSecTransformPtr transform); static int xmlSecOpenSSLSignatureLegacySetKeyReq (xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq); static int xmlSecOpenSSLSignatureLegacySetKey (xmlSecTransformPtr transform, xmlSecKeyPtr key); static int xmlSecOpenSSLSignatureLegacyVerify (xmlSecTransformPtr transform, const xmlSecByte* data, xmlSecSize dataSize, xmlSecTransformCtxPtr transformCtx); static int xmlSecOpenSSLSignatureLegacyExecute (xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx); static int xmlSecOpenSSLSignatureLegacyCheckId(xmlSecTransformPtr transform) { #ifndef XMLSEC_NO_RIPEMD160 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaRipemd160Id)) { return(1); } else #endif /* XMLSEC_NO_RIPEMD160 */ #ifndef XMLSEC_NO_SHA1 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha1Id)) { return(1); } else #endif /* XMLSEC_NO_SHA1 */ #ifndef XMLSEC_NO_SHA224 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha224Id)) { return(1); } else #endif /* XMLSEC_NO_SHA224 */ #ifndef XMLSEC_NO_SHA256 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha256Id)) { return(1); } else #endif /* XMLSEC_NO_SHA256 */ #ifndef XMLSEC_NO_SHA384 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha384Id)) { return(1); } else #endif /* XMLSEC_NO_SHA384 */ #ifndef XMLSEC_NO_SHA512 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha512Id)) { return(1); } else #endif /* XMLSEC_NO_SHA512 */ #ifndef XMLSEC_NO_SHA3 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha3_224Id)) { return(1); } else if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha3_256Id)) { return(1); } else if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha3_384Id)) { return(1); } else if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha3_512Id)) { return(1); } else #endif /* XMLSEC_NO_SHA3 */ { return(0); } } /* small helper macro to reduce clutter in the code */ #define XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, digestVal) \ (ctx)->digest = (digestVal) /* Helper macros to define the transform klass */ #define XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS_EX(name, readNode) \ static xmlSecTransformKlass xmlSecOpenSSL ## name ## Klass = { \ sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ \ xmlSecOpenSSLSignatureLegacySize, /* xmlSecSize objSize */ \ xmlSecName ## name, /* const xmlChar* name; */ \ xmlSecHref ## name, /* const xmlChar* href; */ \ xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ \ xmlSecOpenSSLSignatureLegacyInitialize, /* xmlSecTransformInitializeMethod initialize; */ \ xmlSecOpenSSLSignatureLegacyFinalize, /* xmlSecTransformFinalizeMethod finalize; */ \ readNode, /* xmlSecTransformNodeReadMethod readNode; */ \ NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ \ xmlSecOpenSSLSignatureLegacySetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ \ xmlSecOpenSSLSignatureLegacySetKey, /* xmlSecTransformSetKeyMethod setKey; */ \ xmlSecOpenSSLSignatureLegacyVerify, /* xmlSecTransformVerifyMethod verify; */ \ xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ \ xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ \ xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ \ NULL, /* xmlSecTransformPushXmlMethod pushXml; */ \ NULL, /* xmlSecTransformPopXmlMethod popXml; */ \ xmlSecOpenSSLSignatureLegacyExecute, /* xmlSecTransformExecuteMethod execute; */ \ NULL, /* void* reserved0; */ \ NULL, /* void* reserved1; */ \ }; #define XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(name) \ XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS_EX(name, NULL) static int xmlSecOpenSSLSignatureLegacyInitialize(xmlSecTransformPtr transform) { xmlSecOpenSSLSignatureLegacyCtxPtr ctx; int ret; xmlSecAssert2(xmlSecOpenSSLSignatureLegacyCheckId(transform), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLSignatureLegacySize), -1); ctx = xmlSecOpenSSLSignatureLegacyGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); memset(ctx, 0, sizeof(xmlSecOpenSSLSignatureLegacyCtx)); #ifndef XMLSEC_NO_RIPEMD160 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaRipemd160Id)) { XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, EVP_ripemd160()); ctx->keyId = xmlSecOpenSSLKeyDataEcId; ctx->signCallback = xmlSecOpenSSLSignatureLegacyEcdsaSign; ctx->verifyCallback = xmlSecOpenSSLSignatureLegacyEcdsaVerify; } else #endif /* XMLSEC_NO_RIPEMD160 */ #ifndef XMLSEC_NO_SHA1 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha1Id)) { XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, EVP_sha1()); ctx->keyId = xmlSecOpenSSLKeyDataEcId; ctx->signCallback = xmlSecOpenSSLSignatureLegacyEcdsaSign; ctx->verifyCallback = xmlSecOpenSSLSignatureLegacyEcdsaVerify; } else #endif /* XMLSEC_NO_SHA1 */ #ifndef XMLSEC_NO_SHA224 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha224Id)) { XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, EVP_sha224()); ctx->keyId = xmlSecOpenSSLKeyDataEcId; ctx->signCallback = xmlSecOpenSSLSignatureLegacyEcdsaSign; ctx->verifyCallback = xmlSecOpenSSLSignatureLegacyEcdsaVerify; } else #endif /* XMLSEC_NO_SHA224 */ #ifndef XMLSEC_NO_SHA256 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha256Id)) { XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, EVP_sha256()); ctx->keyId = xmlSecOpenSSLKeyDataEcId; ctx->signCallback = xmlSecOpenSSLSignatureLegacyEcdsaSign; ctx->verifyCallback = xmlSecOpenSSLSignatureLegacyEcdsaVerify; } else #endif /* XMLSEC_NO_SHA256 */ #ifndef XMLSEC_NO_SHA384 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha384Id)) { XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, EVP_sha384()); ctx->keyId = xmlSecOpenSSLKeyDataEcId; ctx->signCallback = xmlSecOpenSSLSignatureLegacyEcdsaSign; ctx->verifyCallback = xmlSecOpenSSLSignatureLegacyEcdsaVerify; } else #endif /* XMLSEC_NO_SHA384 */ #ifndef XMLSEC_NO_SHA512 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha512Id)) { XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, EVP_sha512()); ctx->keyId = xmlSecOpenSSLKeyDataEcId; ctx->signCallback = xmlSecOpenSSLSignatureLegacyEcdsaSign; ctx->verifyCallback = xmlSecOpenSSLSignatureLegacyEcdsaVerify; } else #endif /* XMLSEC_NO_SHA512 */ #ifndef XMLSEC_NO_SHA3 if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha3_224Id)) { XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, EVP_sha3_224()); ctx->keyId = xmlSecOpenSSLKeyDataEcId; ctx->signCallback = xmlSecOpenSSLSignatureLegacyEcdsaSign; ctx->verifyCallback = xmlSecOpenSSLSignatureLegacyEcdsaVerify; } else if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha3_256Id)) { XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, EVP_sha3_256()); ctx->keyId = xmlSecOpenSSLKeyDataEcId; ctx->signCallback = xmlSecOpenSSLSignatureLegacyEcdsaSign; ctx->verifyCallback = xmlSecOpenSSLSignatureLegacyEcdsaVerify; } else if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha3_384Id)) { XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, EVP_sha3_384()); ctx->keyId = xmlSecOpenSSLKeyDataEcId; ctx->signCallback = xmlSecOpenSSLSignatureLegacyEcdsaSign; ctx->verifyCallback = xmlSecOpenSSLSignatureLegacyEcdsaVerify; } else if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformEcdsaSha3_512Id)) { XMLSEC_OPENSSL_SIGNATURE_SET_DIGEST(ctx, EVP_sha3_512()); ctx->keyId = xmlSecOpenSSLKeyDataEcId; ctx->signCallback = xmlSecOpenSSLSignatureLegacyEcdsaSign; ctx->verifyCallback = xmlSecOpenSSLSignatureLegacyEcdsaVerify; } else #endif /* XMLSEC_NO_SHA3 */ if(1) { xmlSecInvalidTransfromError(transform) return(-1); } /* create/init digest CTX */ ctx->digestCtx = EVP_MD_CTX_new(); if(ctx->digestCtx == NULL) { xmlSecOpenSSLError("EVP_MD_CTX_new", xmlSecTransformGetName(transform)); xmlSecOpenSSLSignatureLegacyFinalize(transform); return(-1); } ret = EVP_DigestInit(ctx->digestCtx, ctx->digest); if(ret != 1) { xmlSecOpenSSLError("EVP_DigestInit", xmlSecTransformGetName(transform)); xmlSecOpenSSLSignatureLegacyFinalize(transform); return(-1); } /* done */ return(0); } static void xmlSecOpenSSLSignatureLegacyFinalize(xmlSecTransformPtr transform) { xmlSecOpenSSLSignatureLegacyCtxPtr ctx; xmlSecAssert(xmlSecOpenSSLSignatureLegacyCheckId(transform)); xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLSignatureLegacySize)); ctx = xmlSecOpenSSLSignatureLegacyGetCtx(transform); xmlSecAssert(ctx != NULL); if(ctx->pKey != NULL) { EVP_PKEY_free(ctx->pKey); } if(ctx->digestCtx != NULL) { EVP_MD_CTX_free(ctx->digestCtx); } memset(ctx, 0, sizeof(xmlSecOpenSSLSignatureLegacyCtx)); } static int xmlSecOpenSSLSignatureLegacySetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { xmlSecOpenSSLSignatureLegacyCtxPtr ctx; EVP_PKEY* pKey; xmlSecAssert2(xmlSecOpenSSLSignatureLegacyCheckId(transform), -1); xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLSignatureLegacySize), -1); xmlSecAssert2(key != NULL, -1); ctx = xmlSecOpenSSLSignatureLegacyGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->digest != NULL, -1); xmlSecAssert2(ctx->keyId != NULL, -1); xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1); pKey = xmlSecOpenSSLKeyGetEvp(key); if(pKey == NULL) { xmlSecInternalError("xmlSecOpenSSLKeyGetEvp", xmlSecTransformGetName(transform)); return(-1); } if(ctx->pKey != NULL) { EVP_PKEY_free(ctx->pKey); } ctx->pKey = xmlSecOpenSSLEvpKeyDup(pKey); if(ctx->pKey == NULL) { xmlSecInternalError("xmlSecOpenSSLEvpKeyDup", xmlSecTransformGetName(transform)); return(-1); } return(0); } static int xmlSecOpenSSLSignatureLegacySetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { xmlSecOpenSSLSignatureLegacyCtxPtr ctx; xmlSecAssert2(xmlSecOpenSSLSignatureLegacyCheckId(transform), -1); xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLSignatureLegacySize), -1); xmlSecAssert2(keyReq != NULL, -1); ctx = xmlSecOpenSSLSignatureLegacyGetCtx(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); } static int xmlSecOpenSSLSignatureLegacyVerify(xmlSecTransformPtr transform, const xmlSecByte* data, xmlSecSize dataSize, xmlSecTransformCtxPtr transformCtx) { xmlSecOpenSSLSignatureLegacyCtxPtr ctx; int ret; xmlSecAssert2(xmlSecOpenSSLSignatureLegacyCheckId(transform), -1); xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLSignatureLegacySize), -1); xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); xmlSecAssert2(data != NULL, -1); xmlSecAssert2(transformCtx != NULL, -1); ctx = xmlSecOpenSSLSignatureLegacyGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->verifyCallback != NULL, -1); xmlSecAssert2(ctx->dgstSize > 0, -1); ret = (ctx->verifyCallback)(ctx, transformCtx, data, dataSize); if(ret < 0) { xmlSecInternalError("verifyCallback", xmlSecTransformGetName(transform)); return(-1); } /* check signature results */ if(ret == 1) { transform->status = xmlSecTransformStatusOk; } else { xmlSecOtherError(XMLSEC_ERRORS_R_DATA_NOT_MATCH, xmlSecTransformGetName(transform), "ctx->verifyCallback: signature verification failed"); transform->status = xmlSecTransformStatusFail; } /* done */ return(0); } static int xmlSecOpenSSLSignatureLegacyExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { xmlSecOpenSSLSignatureLegacyCtxPtr ctx; xmlSecBufferPtr in, out; xmlSecSize inSize; xmlSecSize outSize; int ret; xmlSecAssert2(xmlSecOpenSSLSignatureLegacyCheckId(transform), -1); xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLSignatureLegacySize), -1); xmlSecAssert2(transformCtx != NULL, -1); ctx = xmlSecOpenSSLSignatureLegacyGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->signCallback != NULL, -1); xmlSecAssert2(ctx->verifyCallback != NULL, -1); in = &(transform->inBuf); out = &(transform->outBuf); inSize = xmlSecBufferGetSize(in); outSize = xmlSecBufferGetSize(out); ctx = xmlSecOpenSSLSignatureLegacyGetCtx(transform); xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->digest != NULL, -1); xmlSecAssert2(ctx->digestCtx != NULL, -1); xmlSecAssert2(ctx->pKey != NULL, -1); if(transform->status == xmlSecTransformStatusNone) { xmlSecAssert2(outSize == 0, -1); transform->status = xmlSecTransformStatusWorking; } if((transform->status == xmlSecTransformStatusWorking) && (inSize > 0)) { xmlSecAssert2(outSize == 0, -1); ret = EVP_DigestUpdate(ctx->digestCtx, xmlSecBufferGetData(in), inSize); if(ret != 1) { xmlSecOpenSSLError("EVP_DigestUpdate", xmlSecTransformGetName(transform)); return(-1); } ret = xmlSecBufferRemoveHead(in, inSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferRemoveHead", xmlSecTransformGetName(transform)); return(-1); } } if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) { xmlSecAssert2(outSize == 0, -1); ret = EVP_DigestFinal(ctx->digestCtx, ctx->dgst, &ctx->dgstSize); if(ret != 1) { xmlSecOpenSSLError("EVP_DigestFinal", xmlSecTransformGetName(transform)); return(-1); } xmlSecAssert2(ctx->dgstSize > 0, -1); /* sign right away, verify will wait till separate call */ if(transform->operation == xmlSecTransformOperationSign) { ret = (ctx->signCallback)(ctx, transformCtx, out); if(ret < 0) { xmlSecInternalError("signCallback", xmlSecTransformGetName(transform)); return(-1); } } /* done! */ 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); } /****************************************************************************** * * ECDSA EVP * * NIST-IR-7802 (TMSAD) specifies ECDSA signature packing not supported by * OpenSSL so we created our own EVP_MD. * * http://csrc.nist.gov/publications/PubsNISTIRs.html#NIST-IR-7802 * * The ECDSA algorithm signature is a pair of integers referred to as (r, s). * The <dsig:SignatureValue/> consists of the base64 [RFC2045] 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 Section 4.1 of RFC 3447 [PKCS1] with the xLen parameter equal * to the size of the base point order of the curve in bytes (32 for the * P-256 curve and 66 for the P-521 curve). * *****************************************************************************/ static xmlSecOpenSSLSizeT xmlSecOpenSSLSignatureLegacyEcdsaSignatureHalfLen(EVP_PKEY* pKey) { const EC_GROUP *group = NULL; BIGNUM *order = NULL; EC_KEY* ecKey = NULL; xmlSecOpenSSLSizeT signHalfLen; xmlSecOpenSSLSizeT res = 0; xmlSecAssert2(pKey != NULL, 0); /* get key */ ecKey = EVP_PKEY_get1_EC_KEY(pKey); if(ecKey == NULL) { xmlSecOpenSSLError("EVP_PKEY_get1_EC_KEY", NULL); goto done; } group = EC_KEY_get0_group(ecKey); if(group == NULL) { xmlSecOpenSSLError("EC_KEY_get0_group", NULL); goto done; } order = BN_new(); if(order == NULL) { xmlSecOpenSSLError("BN_new", NULL); goto done; } if(EC_GROUP_get_order(group, order, NULL) != 1) { xmlSecOpenSSLError("EC_GROUP_get_order", NULL); goto done; } signHalfLen = BN_num_bytes(order); if(signHalfLen <= 0) { xmlSecOpenSSLError("BN_num_bytes", NULL); goto done; } /* success */ res = signHalfLen; done: /* cleanup */ if(order != NULL) { BN_clear_free(order); } if(ecKey != NULL) { EC_KEY_free(ecKey); } return(res); } static ECDSA_SIG* xmlSecOpenSSLSignatureLegacyEcdsaSignImpl(EVP_PKEY* pKey, const xmlSecByte* buf, xmlSecSize bufSize) { EC_KEY* ecKey = NULL; ECDSA_SIG* sig = NULL; xmlSecOpenSSLSizeT dgstLen; ECDSA_SIG* res = NULL; xmlSecAssert2(pKey != NULL, NULL); xmlSecAssert2(buf != NULL, NULL); xmlSecAssert2(bufSize > 0, NULL); /* get key */ ecKey = EVP_PKEY_get1_EC_KEY(pKey); if(ecKey == NULL) { xmlSecOpenSSLError("EVP_PKEY_get1_DSA", NULL); goto done; } /* sign */ XMLSEC_OPENSSL_SAFE_CAST_SIZE_TO_SIZE_T(bufSize, dgstLen, goto done, NULL); sig = ECDSA_do_sign(buf, dgstLen, ecKey); if(sig == NULL) { xmlSecOpenSSLError("ECDSA_do_sign", NULL); goto done; } /* success */ res = sig; sig = NULL; done: if(sig != NULL) { ECDSA_SIG_free(sig); } if(ecKey != NULL) { EC_KEY_free(ecKey); } return(res); } static int xmlSecOpenSSLSignatureLegacyEcdsaVerifyImpl( EVP_PKEY* pKey, ECDSA_SIG* sig, const xmlSecByte* buf, xmlSecSize bufSize ) { EC_KEY* ecKey = NULL; xmlSecOpenSSLSizeT bufLen; int ret; int res = -1; xmlSecAssert2(pKey != NULL, -1); xmlSecAssert2(sig != NULL, -1); xmlSecAssert2(buf != NULL, -1); xmlSecAssert2(bufSize > 0, -1); /* get key */ ecKey = EVP_PKEY_get1_EC_KEY(pKey); if(ecKey == NULL) { xmlSecOpenSSLError("EVP_PKEY_get1_DSA", NULL); goto done; } /* verify */ XMLSEC_OPENSSL_SAFE_CAST_SIZE_TO_SIZE_T(bufSize, bufLen, goto done, NULL); ret = ECDSA_do_verify(buf, bufLen, sig, ecKey); if(ret < 0) { xmlSecOpenSSLError("ECDSA_do_verify", NULL); goto done; } /* success */ res = ret; done: /* cleanup */ if(ecKey != NULL) { EC_KEY_free(ecKey); } return(res); } static int xmlSecOpenSSLSignatureLegacyEcdsa_OpenSSLToXmlDsig( xmlSecOpenSSLSignatureLegacyCtxPtr ctx, xmlSecTransformCtxPtr transformCtx, ECDSA_SIG* sig, xmlSecBufferPtr out ) { const BIGNUM* rr = NULL; const BIGNUM* ss = NULL; xmlSecByte* outData = NULL; xmlSecSize outSize; xmlSecOpenSSLSizeT signHalfLen, rLen, sLen; int ret; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->pKey != NULL, -1); xmlSecAssert2(transformCtx != NULL, -1); xmlSecAssert2(sig != NULL, -1); xmlSecAssert2(out != NULL, -1); /* however some implementations (e.g. Java) just put ASN1 structure in the signature * https://github.com/lsh123/xmlsec/issues/995 */ if((transformCtx->flags & XMLSEC_TRANSFORMCTX_FLAGS_SUPPORT_ASN1_SIGNATURE_VALUES) != 0) { ret = i2d_ECDSA_SIG(sig, &outData); /* ret is size of signature on success */ if (ret < 0) { xmlSecOpenSSLError("i2d_ECDSA_SIG", NULL); return(-1); } outSize = (xmlSecSize)ret; ret = xmlSecBufferSetData(out, outData, outSize); if(ret < 0) { xmlSecInternalError("xmlSecBufferSetData", NULL); OPENSSL_free(outData); return(-1); } /* done */ OPENSSL_free(outData); return(0); } /* calculate signature size */ signHalfLen = xmlSecOpenSSLSignatureLegacyEcdsaSignatureHalfLen(ctx->pKey); if(signHalfLen <= 0) { xmlSecInternalError("xmlSecOpenSSLSignatureLegacyEcdsaSignatureHalfLen", NULL); return(-1); } /* get signature components */ ECDSA_SIG_get0(sig, &rr, &ss); if((rr == NULL) || (ss == NULL)) { xmlSecOpenSSLError("ECDSA_SIG_get0", NULL); return(-1); } /* check sizes */ rLen = BN_num_bytes(rr); if ((rLen <= 0) || (rLen > signHalfLen)) { xmlSecInvalidDataError("Signature rr length is zero or greater than expected based on key size", NULL); return(-1); } sLen = BN_num_bytes(ss); if ((sLen <= 0) || (sLen > signHalfLen)) { xmlSecInvalidDataError("Signature ss length is zero or greater than expected based on key size", NULL); return(-1); } /* allocate buffer */ XMLSEC_OPENSSL_SAFE_CAST_SIZE_T_TO_SIZE(2 * signHalfLen, outSize, return(-1), NULL); ret = xmlSecBufferSetSize(out, outSize); if(ret < 0) { xmlSecInternalError2("xmlSecBufferSetSize", NULL, "size=" XMLSEC_SIZE_FMT, outSize); return(-1); } outData = xmlSecBufferGetData(out); xmlSecAssert2(outData != NULL, -1); /* write components */ xmlSecAssert2((rLen + sLen) <= 2 * signHalfLen, -1); memset(outData, 0, outSize); (void)BN_bn2bin(rr, outData + signHalfLen - rLen); (void)BN_bn2bin(ss, outData + 2 * signHalfLen - sLen); /* success */ return(0); } static int xmlSecOpenSSLSignatureLegacyEcdsaSign( xmlSecOpenSSLSignatureLegacyCtxPtr ctx, xmlSecTransformCtxPtr transformCtx, xmlSecBufferPtr out ) { ECDSA_SIG* sig = NULL; int ret; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->pKey != NULL, -1); xmlSecAssert2(ctx->dgstSize > 0, -1); xmlSecAssert2(ctx->dgstSize <= sizeof(ctx->dgst), -1); xmlSecAssert2(transformCtx != NULL, -1); xmlSecAssert2(out != NULL, -1); /* sign */ sig = xmlSecOpenSSLSignatureLegacyEcdsaSignImpl(ctx->pKey, ctx->dgst, ctx->dgstSize); if(sig == NULL) { xmlSecInternalError("xmlSecOpenSSLSignatureLegacyEcdsaSignImpl", NULL); return(-1); } /* convert to XMLDSig format */ ret = xmlSecOpenSSLSignatureLegacyEcdsa_OpenSSLToXmlDsig(ctx, transformCtx, sig, out); if(ret < 0) { xmlSecInternalError("xmlSecOpenSSLSignatureLegacyEcdsaSignImpl", NULL); ECDSA_SIG_free(sig); return(-1); } ECDSA_SIG_free(sig); /* done */ return(0); } static ECDSA_SIG* xmlSecOpenSSLSignatureLegacyEcdsa_XmlDSigToOpenSSL( xmlSecOpenSSLSignatureLegacyCtxPtr ctx, xmlSecTransformCtxPtr transformCtx, const xmlSecByte* signData, xmlSecSize signSize ) { ECDSA_SIG* sig = NULL; BIGNUM* rr = NULL; BIGNUM* ss = NULL; xmlSecOpenSSLSizeT signLen, signHalfLen; int ret; xmlSecAssert2(ctx != NULL, NULL); xmlSecAssert2(ctx->pKey != NULL, NULL); xmlSecAssert2(transformCtx != NULL, NULL); xmlSecAssert2(signData != NULL, NULL); /* however some implementations (e.g. Java) just put ASN1 structure in the signature * https://github.com/lsh123/xmlsec/issues/995 */ if((transformCtx->flags & XMLSEC_TRANSFORMCTX_FLAGS_SUPPORT_ASN1_SIGNATURE_VALUES) != 0) { int dataLen; XMLSEC_SAFE_CAST_SIZE_TO_INT(signSize, dataLen, return(NULL), NULL); sig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&signData, dataLen); if (sig == NULL) { xmlSecOpenSSLError("d2i_ECDSA_SIG()", NULL); return(NULL); } return(sig); } /* calculate signature size */ signHalfLen = xmlSecOpenSSLSignatureLegacyEcdsaSignatureHalfLen(ctx->pKey); if(signHalfLen <= 0) { xmlSecInternalError("xmlSecOpenSSLSignatureLegacyEcdsaSignatureHalfSize", NULL); return(NULL); } /* check size: we expect the r and s to be the same size and match the size of * the key (RFC 6931) */ XMLSEC_OPENSSL_SAFE_CAST_SIZE_TO_SIZE_T(signSize, signLen, return(NULL), NULL); if(signLen == 2 * signHalfLen) { /* good, do nothing */ } else if((signLen < 2 * signHalfLen) && (signLen % 2 == 0)) { /* however some implementations (e.g. Java) cut leading zeros: * https://github.com/lsh123/xmlsec/issues/228 */ signHalfLen = signLen / 2; } else if((signLen > 2 * signHalfLen) && (signLen % 2 == 0)) { /* however some implementations (e.g. Java) add leading zeros: * https://github.com/lsh123/xmlsec/issues/941*/ signHalfLen = signLen / 2; } else { xmlSecInvalidDataError("Signature length doesn't match key size", NULL); return(NULL); } /* create/read signature */ sig = ECDSA_SIG_new(); if (sig == NULL) { xmlSecOpenSSLError("DSA_SIG_new", NULL); return(NULL); } rr = BN_bin2bn(signData, signHalfLen, NULL); if(rr == NULL) { xmlSecOpenSSLError("BN_bin2bn(sig->r)", NULL); ECDSA_SIG_free(sig); return(NULL); } ss = BN_bin2bn(signData + signHalfLen, signHalfLen, NULL); if(ss == NULL) { xmlSecOpenSSLError("BN_bin2bn(sig->s)", NULL); BN_clear_free(rr); ECDSA_SIG_free(sig); return(NULL); } ret = ECDSA_SIG_set0(sig, rr, ss); if(ret == 0) { xmlSecOpenSSLError("ECDSA_SIG_set0()", NULL); BN_clear_free(rr); BN_clear_free(ss); ECDSA_SIG_free(sig); return(NULL); } /* done */ return(sig); } static int xmlSecOpenSSLSignatureLegacyEcdsaVerify( xmlSecOpenSSLSignatureLegacyCtxPtr ctx, xmlSecTransformCtxPtr transformCtx, const xmlSecByte* signData, xmlSecSize signSize ){ ECDSA_SIG* sig = NULL; int ret; xmlSecAssert2(ctx != NULL, -1); xmlSecAssert2(ctx->pKey != NULL, -1); xmlSecAssert2(ctx->dgstSize > 0, -1); xmlSecAssert2(ctx->dgstSize <= sizeof(ctx->dgst), -1); xmlSecAssert2(transformCtx != NULL, -1); xmlSecAssert2(signData != NULL, -1); /* get signature value */ sig = xmlSecOpenSSLSignatureLegacyEcdsa_XmlDSigToOpenSSL(ctx, transformCtx, signData, signSize); if(sig == NULL) { xmlSecInternalError("xmlSecOpenSSLSignatureLegacyEcdsa_XmlDSigToOpenSSL", NULL); return(-1); } /* verify signature */ ret = xmlSecOpenSSLSignatureLegacyEcdsaVerifyImpl(ctx->pKey, sig, ctx->dgst, ctx->dgstSize); if(ret < 0) { xmlSecInternalError("xmlSecOpenSSLSignatureLegacyEcdsaVerifyImpl", NULL); ECDSA_SIG_free(sig); return(-1); } ECDSA_SIG_free(sig); /* return 1 for good signatures and 0 for bad */ return ((ret > 0) ? 1 : 0); } #ifndef XMLSEC_NO_RIPEMD160 /****************************************************************************** * * ECDSA-RIPEMD160 signature transform * *****************************************************************************/ XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(EcdsaRipemd160) /** * @brief The ECDSA-RIPEMD160 signature transform klass. * @return ECDSA-RIPEMD160 signature transform klass. */ xmlSecTransformId xmlSecOpenSSLTransformEcdsaRipemd160GetKlass(void) { return(&xmlSecOpenSSLEcdsaRipemd160Klass); } #endif /* XMLSEC_NO_RIPEMD160 */ #ifndef XMLSEC_NO_SHA1 /****************************************************************************** * * ECDSA-SHA1 signature transform * *****************************************************************************/ XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(EcdsaSha1) /** * @brief The ECDSA-SHA1 signature transform klass. * @return ECDSA-SHA1 signature transform klass. */ xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha1GetKlass(void) { return(&xmlSecOpenSSLEcdsaSha1Klass); } #endif /* XMLSEC_NO_SHA1 */ #ifndef XMLSEC_NO_SHA224 /****************************************************************************** * * ECDSA-SHA2-224 signature transform * *****************************************************************************/ XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(EcdsaSha224) /** * @brief The ECDSA-SHA2-224 signature transform klass. * @return ECDSA-SHA2-224 signature transform klass. */ xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha224GetKlass(void) { return(&xmlSecOpenSSLEcdsaSha224Klass); } #endif /* XMLSEC_NO_SHA224 */ #ifndef XMLSEC_NO_SHA256 /****************************************************************************** * * ECDSA-SHA2-256 signature transform * *****************************************************************************/ XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(EcdsaSha256) /** * @brief The ECDSA-SHA2-256 signature transform klass. * @return ECDSA-SHA2-256 signature transform klass. */ xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha256GetKlass(void) { return(&xmlSecOpenSSLEcdsaSha256Klass); } #endif /* XMLSEC_NO_SHA256 */ #ifndef XMLSEC_NO_SHA384 /****************************************************************************** * * ECDSA-SHA2-384 signature transform * *****************************************************************************/ XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(EcdsaSha384) /** * @brief The ECDSA-SHA2-384 signature transform klass. * @return ECDSA-SHA2-384 signature transform klass. */ xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha384GetKlass(void) { return(&xmlSecOpenSSLEcdsaSha384Klass); } #endif /* XMLSEC_NO_SHA384 */ #ifndef XMLSEC_NO_SHA512 /****************************************************************************** * * ECDSA-SHA2-512 signature transform * *****************************************************************************/ XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(EcdsaSha512) /** * @brief The ECDSA-SHA2-512 signature transform klass. * @return ECDSA-SHA2-512 signature transform klass. */ xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha512GetKlass(void) { return(&xmlSecOpenSSLEcdsaSha512Klass); } #endif /* XMLSEC_NO_SHA512 */ #ifndef XMLSEC_NO_SHA3 /****************************************************************************** * * ECDSA-SHA3-224 signature transform * *****************************************************************************/ XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(EcdsaSha3_224) /** * @brief The ECDSA-SHA3-224 signature transform klass. * @return ECDSA-SHA3-224 signature transform klass. */ xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha3_224GetKlass(void) { return(&xmlSecOpenSSLEcdsaSha3_224Klass); } XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(EcdsaSha3_256) /** * @brief The ECDSA-SHA3-256 signature transform klass. * @return ECDSA-SHA3-256 signature transform klass. */ xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha3_256GetKlass(void) { return(&xmlSecOpenSSLEcdsaSha3_256Klass); } XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(EcdsaSha3_384) /** * @brief The ECDSA-SHA3-384 signature transform klass. * @return ECDSA-SHA3-384 signature transform klass. */ xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha3_384GetKlass(void) { return(&xmlSecOpenSSLEcdsaSha3_384Klass); } XMLSEC_OPENSSL_EVP_SIGNATURE_LEGACY_KLASS(EcdsaSha3_512) /** * @brief The ECDSA-SHA3-512 signature transform klass. * @return ECDSA-SHA3-512 signature transform klass. */ xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha3_512GetKlass(void) { return(&xmlSecOpenSSLEcdsaSha3_512Klass); } #endif /* XMLSEC_NO_SHA3 */ #else /* !defined(XMLSEC_OPENSSL_API_300) && !defined(XMLSEC_NO_EC) */ /* ISO C forbids an empty translation unit */ typedef int make_iso_compilers_happy; #endif /* !defined(XMLSEC_OPENSSL_API_300) && !defined(XMLSEC_NO_EC) */