From a2448ac7a26c64be27b81a26a34cb933e4fb899d Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Sat, 25 Feb 2017 01:03:19 +0100 Subject: [PATCH] nss: add ECDSA-SHA256 support (#83) Conflicts: configure.ac src/nss/signatures.c --- include/xmlsec/nss/crypto.h | 30 +++++++++ include/xmlsec/nss/symbols.h | 1 + src/nss/README | 2 +- src/nss/crypto.c | 7 +++ src/nss/pkikeys.c | 141 +++++++++++++++++++++++++++++++++++++++++++ src/nss/signatures.c | 124 ++++++++++++++++++++++++++++++++----- 6 files changed, 290 insertions(+), 15 deletions(-) diff --git a/include/xmlsec/nss/crypto.h b/include/xmlsec/nss/crypto.h index 87f31bf..adc73c8 100644 --- a/include/xmlsec/nss/crypto.h +++ b/include/xmlsec/nss/crypto.h @@ -189,6 +189,36 @@ XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecNssTransformDsaSha1GetKlass(void); /******************************************************************** * + * ECDSA transform + * + *******************************************************************/ +#ifndef XMLSEC_NO_ECDSA + +/** + * xmlSecNssKeyDataEcdsaId: + * + * The ECDSA key klass. + */ +#define xmlSecNssKeyDataEcdsaId xmlSecNssKeyDataEcdsaGetKlass() +XMLSEC_CRYPTO_EXPORT xmlSecKeyDataId xmlSecNssKeyDataEcdsaGetKlass(void); + +#ifndef XMLSEC_NO_SHA256 + +/** + * xmlSecNssTransformEcdsaSha256Id: + * + * The ECDSA SHA256 signature transform klass. + */ +#define xmlSecNssTransformEcdsaSha256Id xmlSecNssTransformEcdsaSha256GetKlass() +XMLSEC_CRYPTO_EXPORT xmlSecTransformId xmlSecNssTransformEcdsaSha256GetKlass(void); + +#endif /* XMLSEC_NO_SHA256 */ + +#endif /* XMLSEC_NO_ECDSA */ + + +/******************************************************************** + * * HMAC transforms * *******************************************************************/ diff --git a/include/xmlsec/nss/symbols.h b/include/xmlsec/nss/symbols.h index 23653ed..499801c 100644 --- a/include/xmlsec/nss/symbols.h +++ b/include/xmlsec/nss/symbols.h @@ -65,6 +65,7 @@ extern "C" { #define xmlSecTransformDes3CbcId xmlSecNssTransformDes3CbcId #define xmlSecTransformKWDes3Id xmlSecNssTransformKWDes3Id #define xmlSecTransformDsaSha1Id xmlSecNssTransformDsaSha1Id +#define xmlSecTransformEcdsaSha256Id xmlSecNssTransformEcdsaSha256Id #define xmlSecTransformHmacMd5Id xmlSecNssTransformHmacMd5Id #define xmlSecTransformHmacRipemd160Id xmlSecNssTransformHmacRipemd160Id #define xmlSecTransformHmacSha1Id xmlSecNssTransformHmacSha1Id diff --git a/src/nss/README b/src/nss/README index 65a0f45..536552e 100644 --- a/src/nss/README +++ b/src/nss/README @@ -1,6 +1,6 @@ WHAT VERSION OF NSS? ------------------------------------------------------------------------ -NSS 3.9 or greater and NSPR 4.4.1 or greater are required. +NSS 3.11.1 or greater and NSPR 4.4.1 or greater are required. KEYS MANAGER ------------------------------------------------------------------------ diff --git a/src/nss/crypto.c b/src/nss/crypto.c index 473429f..81a81d3 100644 --- a/src/nss/crypto.c +++ b/src/nss/crypto.c @@ -124,6 +124,13 @@ xmlSecCryptoGetFunctions_nss(void) { gXmlSecNssFunctions->transformDsaSha1GetKlass = xmlSecNssTransformDsaSha1GetKlass; #endif /* XMLSEC_NO_DSA */ + /******************************* ECDSA ******************************/ +#ifndef XMLSEC_NO_ECDSA +#ifndef XMLSEC_NO_SHA256 + gXmlSecNssFunctions->transformEcdsaSha256GetKlass = xmlSecNssTransformEcdsaSha256GetKlass; +#endif /* XMLSEC_NO_SHA256 */ +#endif /* XMLSEC_NO_ECDSA */ + /******************************* HMAC ********************************/ #ifndef XMLSEC_NO_HMAC diff --git a/src/nss/pkikeys.c b/src/nss/pkikeys.c index 896c245..1d601d2 100644 --- a/src/nss/pkikeys.c +++ b/src/nss/pkikeys.c @@ -257,6 +257,19 @@ xmlSecNssPKIAdoptKey(SECKEYPrivateKey *privkey, } break; #endif /* XMLSEC_NO_DSA */ +#ifndef XMLSEC_NO_ECDSA + case ecKey: + data = xmlSecKeyDataCreate(xmlSecNssKeyDataEcdsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecNssKeyDataEcdsaId"); + return(NULL); + } + break; +#endif /* XMLSEC_NO_ECDSA */ default: xmlSecError(XMLSEC_ERRORS_HERE, NULL, @@ -1564,5 +1577,133 @@ xmlSecNssKeyDataRsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { #endif /* XMLSEC_NO_RSA */ +#ifndef XMLSEC_NO_ECDSA +static int xmlSecNssKeyDataEcdsaInitialize(xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataEcdsaDuplicate(xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecNssKeyDataEcdsaFinalize(xmlSecKeyDataPtr data); + +static xmlSecKeyDataType xmlSecNssKeyDataEcdsaGetType(xmlSecKeyDataPtr data); +static xmlSecSize xmlSecNssKeyDataEcdsaGetSize(xmlSecKeyDataPtr data); +static void xmlSecNssKeyDataEcdsaDebugDump(xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecNssKeyDataEcdsaDebugXmlDump(xmlSecKeyDataPtr data, + FILE* output); + +static xmlSecKeyDataKlass xmlSecNssKeyDataEcdsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecNssPKIKeyDataSize, + + /* data */ + xmlSecNameECDSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefECDSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeECDSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecNssKeyDataEcdsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecNssKeyDataEcdsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecNssKeyDataEcdsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + NULL, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecNssKeyDataEcdsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecNssKeyDataEcdsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + NULL, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + NULL, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecNssKeyDataEcdsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecNssKeyDataEcdsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeyDataEcdsaGetKlass: + * + * The ECDSA key data klass. + * + * Returns: pointer to ECDSA key data klass. + */ +xmlSecKeyDataId +xmlSecNssKeyDataEcdsaGetKlass(void) { + return(&xmlSecNssKeyDataEcdsaKlass); +} + +static int +xmlSecNssKeyDataEcdsaInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataEcdsaId), -1); + + return(xmlSecNssPKIKeyDataInitialize(data)); +} + +static int +xmlSecNssKeyDataEcdsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecNssKeyDataEcdsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecNssKeyDataEcdsaId), -1); + + return(xmlSecNssPKIKeyDataDuplicate(dst, src)); +} + +static void +xmlSecNssKeyDataEcdsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataEcdsaId)); + + xmlSecNssPKIKeyDataFinalize(data); +} + +static xmlSecKeyDataType +xmlSecNssKeyDataEcdsaGetType(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataEcdsaId), xmlSecKeyDataTypeUnknown); + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == ecKey, -1); + if (ctx->privkey != NULL) { + return(xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); + } else { + return(xmlSecKeyDataTypePublic); + } +} + +static xmlSecSize +xmlSecNssKeyDataEcdsaGetSize(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataEcdsaId), 0); + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == ecKey, -1); + return(SECKEY_SignatureLen(ctx->pubkey)); +} +static void +xmlSecNssKeyDataEcdsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataEcdsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== ecdsa key: size = %d\n", + xmlSecNssKeyDataEcdsaGetSize(data)); +} + +static void +xmlSecNssKeyDataEcdsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataEcdsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "\n", + xmlSecNssKeyDataEcdsaGetSize(data)); +} +#endif /* XMLSEC_NO_ECDSA */ diff --git a/src/nss/signatures.c b/src/nss/signatures.c index 4f54170..a8fec2c 100644 --- a/src/nss/signatures.c +++ b/src/nss/signatures.c @@ -83,6 +83,14 @@ xmlSecNssSignatureCheckId(xmlSecTransformPtr transform) { } #endif /* XMLSEC_NO_DSA */ +#ifndef XMLSEC_NO_ECDSA +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformEcdsaSha256Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA256 */ +#endif /* XMLSEC_NO_ECDSA */ + #ifndef XMLSEC_NO_RSA #ifndef XMLSEC_NO_MD5 @@ -139,6 +147,16 @@ xmlSecNssSignatureInitialize(xmlSecTransformPtr transform) { } else #endif /* XMLSEC_NO_DSA */ +#ifndef XMLSEC_NO_ECDSA +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformEcdsaSha256Id)) { + ctx->keyId = xmlSecNssKeyDataEcdsaId; + /* This creates a signature which is ASN1 encoded */ + ctx->alg = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; + } else +#endif /* XMLSEC_NO_SHA256 */ +#endif /* XMLSEC_NO_ECDSA */ + #ifndef XMLSEC_NO_RSA #ifndef XMLSEC_NO_MD5 @@ -331,16 +349,16 @@ xmlSecNssSignatureVerify(xmlSecTransformPtr transform, signature.data = (unsigned char *)data; signature.len = dataSize; - if(ctx->alg == SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) { + if(ctx->alg == SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST || ctx->alg == SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE) { /* This creates a signature which is ASN1 encoded */ SECItem signatureDer; SECStatus statusDer; - statusDer = DSAU_EncodeDerSig(&signatureDer, &signature); + statusDer = DSAU_EncodeDerSigWithLen(&signatureDer, &signature, signature.len); if(statusDer != SECSuccess) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), - "DSAU_EncodeDerSig", + "DSAU_EncodeDerSigWithLen", XMLSEC_ERRORS_R_CRYPTO_FAILED, "error code=%d", PORT_GetError()); @@ -484,20 +502,48 @@ xmlSecNssSignatureExecute(xmlSecTransformPtr transform, int last, xmlSecTransfor return(-1); } - if(ctx->alg == SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) { + if(ctx->alg == SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST || ctx->alg == SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE) { /* This creates a signature which is ASN1 encoded */ SECItem * signatureClr; - signatureClr = DSAU_DecodeDerSig(&signature); - if(signatureClr == NULL) { - xmlSecError(XMLSEC_ERRORS_HERE, - xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), - "DSAU_EncodeDerSig", - XMLSEC_ERRORS_R_CRYPTO_FAILED, - "error code=%d", - PORT_GetError()); - SECITEM_FreeItem(&signature, PR_FALSE); - return(-1); + if(ctx->alg == SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) { + signatureClr = DSAU_DecodeDerSig(&signature); + if(signatureClr == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "DSAU_DecodeDerSig", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", + PORT_GetError()); + SECITEM_FreeItem(&signature, PR_FALSE); + return(-1); + } + } else { + /* In the ECDSA case the signature length depends on the + * key parameters. */ + int signatureSize = PK11_SignatureLen(ctx->u.sig.privkey); + if(signatureSize < 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_SignatureLen", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", + PORT_GetError()); + SECITEM_FreeItem(&signature, PR_FALSE); + return(-1); + } + + signatureClr = DSAU_DecodeDerSigToLen(&signature, signatureSize); + if(signatureClr == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "DSAU_DecodeDerSigToLen", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", + PORT_GetError()); + SECITEM_FreeItem(&signature, PR_FALSE); + return(-1); + } } ret = xmlSecBufferSetData(out, signatureClr->data, signatureClr->len); @@ -598,6 +644,56 @@ xmlSecNssTransformDsaSha1GetKlass(void) { #endif /* XMLSEC_NO_DSA */ +#ifndef XMLSEC_NO_ECDSA +#ifndef XMLSEC_NO_SHA256 +/**************************************************************************** + * + * ECDSA-SHA256 signature transform + * + ***************************************************************************/ + +static xmlSecTransformKlass xmlSecNssEcdsaSha256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameEcdsaSha256, /* const xmlChar* name; */ + xmlSecHrefEcdsaSha256, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecNssSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecNssSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecNssSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformEcdsaSha256GetKlass: + * + * The ECDSA-SHA256 signature transform klass. + * + * Returns: ECDSA-SHA256 signature transform klass. + */ +xmlSecTransformId +xmlSecNssTransformEcdsaSha256GetKlass(void) { + return(&xmlSecNssEcdsaSha256Klass); +} + +#endif /* XMLSEC_NO_SHA256 */ +#endif /* XMLSEC_NO_ECDSA */ + #ifndef XMLSEC_NO_RSA #ifndef XMLSEC_NO_MD5 -- 2.10.2