diff options
Diffstat (limited to 'src/nss/pkikeys.c')
-rw-r--r-- | src/nss/pkikeys.c | 1554 |
1 files changed, 1554 insertions, 0 deletions
diff --git a/src/nss/pkikeys.c b/src/nss/pkikeys.c new file mode 100644 index 00000000..ae9e29b4 --- /dev/null +++ b/src/nss/pkikeys.c @@ -0,0 +1,1554 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#include "globals.h" + +#include <string.h> + +#include <pk11func.h> +#include <keyhi.h> +#include <pk11pqg.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/nss/crypto.h> +#include <xmlsec/nss/bignum.h> +#include <xmlsec/nss/pkikeys.h> + +/************************************************************************** + * + * Internal NSS PKI key CTX + * + *************************************************************************/ +typedef struct _xmlSecNssPKIKeyDataCtx xmlSecNssPKIKeyDataCtx, + *xmlSecNssPKIKeyDataCtxPtr; +struct _xmlSecNssPKIKeyDataCtx { + SECKEYPublicKey *pubkey; + SECKEYPrivateKey *privkey; +}; + +/****************************************************************************** + * + * PKI key (dsa/rsa) + * + * xmlSecNssPKIKeyDataCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecNssPKIKeyDataSize \ + (sizeof(xmlSecKeyData) + sizeof(xmlSecNssPKIKeyDataCtx)) +#define xmlSecNssPKIKeyDataGetCtx(data) \ + ((xmlSecNssPKIKeyDataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData))) + + +static int xmlSecNssPKIKeyDataInitialize (xmlSecKeyDataPtr data); +static void xmlSecNssPKIKeyDataFinalize (xmlSecKeyDataPtr data); + + +static void xmlSecNSSPKIKeyDataCtxFree (xmlSecNssPKIKeyDataCtxPtr ctx); +static int xmlSecNSSPKIKeyDataCtxDup (xmlSecNssPKIKeyDataCtxPtr ctxDst, + xmlSecNssPKIKeyDataCtxPtr ctxSrc); +static int xmlSecNssPKIKeyDataAdoptKey (xmlSecKeyDataPtr data, + SECKEYPrivateKey *privkey, + SECKEYPublicKey *pubkey); + + +static int +xmlSecNssPKIKeyDataInitialize(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize), -1); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecNssPKIKeyDataCtx)); + + return(0); +} + + +static void +xmlSecNssPKIKeyDataFinalize(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize)); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert(ctx != NULL); + + xmlSecNSSPKIKeyDataCtxFree(ctx); + memset(ctx, 0, sizeof(xmlSecNssPKIKeyDataCtx)); +} + + +static void +xmlSecNSSPKIKeyDataCtxFree(xmlSecNssPKIKeyDataCtxPtr ctx) +{ + xmlSecAssert(ctx != NULL); + if (ctx->privkey != NULL) { + SECKEY_DestroyPrivateKey(ctx->privkey); + ctx->privkey = NULL; + } + + if (ctx->pubkey) + { + SECKEY_DestroyPublicKey(ctx->pubkey); + ctx->pubkey = NULL; + } + +} + +static int +xmlSecNSSPKIKeyDataCtxDup(xmlSecNssPKIKeyDataCtxPtr ctxDst, + xmlSecNssPKIKeyDataCtxPtr ctxSrc) +{ + xmlSecNSSPKIKeyDataCtxFree(ctxDst); + if (ctxSrc->privkey != NULL) { + ctxDst->privkey = SECKEY_CopyPrivateKey(ctxSrc->privkey); + if(ctxDst->privkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SECKEY_CopyPrivateKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } + + if (ctxSrc->pubkey != NULL) { + ctxDst->pubkey = SECKEY_CopyPublicKey(ctxSrc->pubkey); + if(ctxDst->pubkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SECKEY_CopyPublicKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } + return (0); +} + +static int +xmlSecNssPKIKeyDataAdoptKey(xmlSecKeyDataPtr data, + SECKEYPrivateKey *privkey, + SECKEYPublicKey *pubkey) +{ + xmlSecNssPKIKeyDataCtxPtr ctx; + KeyType pubType = nullKey ; + KeyType priType = nullKey ; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize), -1); + + if( privkey != NULL ) { + priType = SECKEY_GetPrivateKeyType( privkey ) ; + } + + if( pubkey != NULL ) { + pubType = SECKEY_GetPublicKeyType( pubkey ) ; + } + + if( priType != nullKey && pubType != nullKey ) { + if( pubType != priType ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + NULL , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + "different type of private and public key" ) ; + return -1 ; + } + } + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + if (ctx->privkey) { + SECKEY_DestroyPrivateKey(ctx->privkey); + } + ctx->privkey = privkey; + + if (ctx->pubkey) { + SECKEY_DestroyPublicKey(ctx->pubkey); + } + ctx->pubkey = pubkey; + + return(0); +} + +/** + * xmlSecNssPKIAdoptKey: + * @privkey: the NSS Private Key handle + * @pubkey: the NSS Public Key handle + * + * Build a KeyData object from the given Private Key and Public + * Key handles. + * + * Returns: pointer to KeyData object or NULL if an error occurs. + */ +xmlSecKeyDataPtr +xmlSecNssPKIAdoptKey(SECKEYPrivateKey *privkey, + SECKEYPublicKey *pubkey) +{ + xmlSecKeyDataPtr data = NULL; + int ret; + KeyType pubType = nullKey ; + KeyType priType = nullKey ; + + if( privkey != NULL ) { + priType = SECKEY_GetPrivateKeyType( privkey ) ; + } + + if( pubkey != NULL ) { + pubType = SECKEY_GetPublicKeyType( pubkey ) ; + } + + if( priType != nullKey && pubType != nullKey ) { + if( pubType != priType ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + NULL , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + "different type of private and public key" ) ; + return( NULL ) ; + } + } + + pubType = priType != nullKey ? priType : pubType ; + switch(pubType) { +#ifndef XMLSEC_NO_RSA + case rsaKey: + data = xmlSecKeyDataCreate(xmlSecNssKeyDataRsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecNssKeyDataRsaId"); + return(NULL); + } + break; +#endif /* XMLSEC_NO_RSA */ +#ifndef XMLSEC_NO_DSA + case dsaKey: + data = xmlSecKeyDataCreate(xmlSecNssKeyDataDsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecNssKeyDataDsaId"); + return(NULL); + } + break; +#endif /* XMLSEC_NO_DSA */ + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_TYPE, + "PKI key type %d not supported", pubType); + return(NULL); + } + + xmlSecAssert2(data != NULL, NULL); + ret = xmlSecNssPKIKeyDataAdoptKey(data, privkey, pubkey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssPKIKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(NULL); + } + return(data); +} + +/** + * xmlSecNssPKIKeyDataGetPubKey: + * @data: the pointer to NSS Key data. + * + * Gets the Public Key from the key data. + * + * Returns: pointer to SECKEYPublicKey or NULL if an error occurs. + * Caller is responsible for freeing the key when done + */ +SECKEYPublicKey * +xmlSecNssPKIKeyDataGetPubKey(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + SECKEYPublicKey *ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize), NULL); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->pubkey != NULL, NULL); + + ret = SECKEY_CopyPublicKey(ctx->pubkey); + return(ret); +} + +/** + * xmlSecNssPKIKeyDataGetPrivKey: + * @data: the pointer to NSS Key data. + * + * Gets the Private Key from the key data. + * + * Returns: pointer to SECKEYPrivateKey or NULL if an error occurs. + * Caller is responsible for freeing the key when done + */ +SECKEYPrivateKey* +xmlSecNssPKIKeyDataGetPrivKey(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + SECKEYPrivateKey* ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize), NULL); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->privkey != NULL, NULL); + + ret = SECKEY_CopyPrivateKey(ctx->privkey); + return(ret); +} + +/** + * xmlSecNssPKIKeyDataGetKeyType: + * @data: the pointer to NSS Key data. + * + * Gets the Key Type from the key data. + * + * Returns: Key Type + */ +KeyType +xmlSecNssPKIKeyDataGetKeyType(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + KeyType kt; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), nullKey); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize), nullKey); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, nullKey); + + if (ctx->pubkey != NULL) { + kt = SECKEY_GetPublicKeyType(ctx->pubkey); + } else { + kt = SECKEY_GetPrivateKeyType(ctx->privkey); + } + return(kt); +} + +/** + * xmlSecNssPKIKeyDataDuplicate + * @dst: the pointer to NSS Key data to copy to. + * @src: the pointer to NSS Key data to copy from. + * + * Duplicates the keydata from src to dst + * + * Returns: -1 on error, 0 on success + */ +int +xmlSecNssPKIKeyDataDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecNssPKIKeyDataCtxPtr ctxDst; + xmlSecNssPKIKeyDataCtxPtr ctxSrc; + + xmlSecAssert2(xmlSecKeyDataIsValid(dst), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(dst, xmlSecNssPKIKeyDataSize), -1); + xmlSecAssert2(xmlSecKeyDataIsValid(src), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(src, xmlSecNssPKIKeyDataSize), -1); + + ctxDst = xmlSecNssPKIKeyDataGetCtx(dst); + xmlSecAssert2(ctxDst != NULL, -1); + + ctxSrc = xmlSecNssPKIKeyDataGetCtx(src); + xmlSecAssert2(ctxSrc != NULL, -1); + + if (xmlSecNSSPKIKeyDataCtxDup(ctxDst, ctxSrc) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecNssPKIKeydataCtxDup", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +#ifndef XMLSEC_NO_DSA +/************************************************************************** + * + * <dsig:DSAKeyValue> processing + * + * + * The DSAKeyValue Element (http://www.w3.org/TR/xmldsig-core/#sec-DSAKeyValue) + * + * DSA keys and the DSA signature algorithm are specified in [DSS]. + * DSA public key values can have the following fields: + * + * * P - a prime modulus meeting the [DSS] requirements + * * Q - an integer in the range 2**159 < Q < 2**160 which is a prime + * divisor of P-1 + * * G - an integer with certain properties with respect to P and Q + * * Y - G**X mod P (where X is part of the private key and not made + * public) + * * J - (P - 1) / Q + * * seed - a DSA prime generation seed + * * pgenCounter - a DSA prime generation counter + * + * Parameter J is available for inclusion solely for efficiency as it is + * calculatable from P and Q. Parameters seed and pgenCounter are used in the + * DSA prime number generation algorithm specified in [DSS]. As such, they are + * optional but must either both be present or both be absent. This prime + * generation algorithm is designed to provide assurance that a weak prime is + * not being used and it yields a P and Q value. Parameters P, Q, and G can be + * public and common to a group of users. They might be known from application + * context. As such, they are optional but P and Q must either both appear or + * both be absent. If all of P, Q, seed, and pgenCounter are present, + * implementations are not required to check if they are consistent and are + * free to use either P and Q or seed and pgenCounter. All parameters are + * encoded as base64 [MIME] values. + * + * Arbitrary-length integers (e.g. "bignums" such as RSA moduli) are + * represented in XML as octet strings as defined by the ds:CryptoBinary type. + * + * Schema Definition: + * + * <element name="DSAKeyValue" type="ds:DSAKeyValueType"/> + * <complexType name="DSAKeyValueType"> + * <sequence> + * <sequence minOccurs="0"> + * <element name="P" type="ds:CryptoBinary"/> + * <element name="Q" type="ds:CryptoBinary"/> + * </sequence> + * <element name="G" type="ds:CryptoBinary" minOccurs="0"/> + * <element name="Y" type="ds:CryptoBinary"/> + * <element name="J" type="ds:CryptoBinary" minOccurs="0"/> + * <sequence minOccurs="0"> + * <element name="Seed" type="ds:CryptoBinary"/> + * <element name="PgenCounter" type="ds:CryptoBinary"/> + * </sequence> + * </sequence> + * </complexType> + * + * DTD Definition: + * + * <!ELEMENT DSAKeyValue ((P, Q)?, G?, Y, J?, (Seed, PgenCounter)?) > + * <!ELEMENT P (#PCDATA) > + * <!ELEMENT Q (#PCDATA) > + * <!ELEMENT G (#PCDATA) > + * <!ELEMENT Y (#PCDATA) > + * <!ELEMENT J (#PCDATA) > + * <!ELEMENT Seed (#PCDATA) > + * <!ELEMENT PgenCounter (#PCDATA) > + * + * ============================================================================ + * + * To support reading/writing private keys an X element added (before Y). + * todo: The current implementation does not support Seed and PgenCounter! + * by this the P, Q and G are *required*! + * + *************************************************************************/ +static int xmlSecNssKeyDataDsaInitialize (xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataDsaDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecNssKeyDataDsaFinalize (xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataDsaXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssKeyDataDsaXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssKeyDataDsaGenerate (xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecNssKeyDataDsaGetType (xmlSecKeyDataPtr data); +static xmlSecSize xmlSecNssKeyDataDsaGetSize (xmlSecKeyDataPtr data); +static void xmlSecNssKeyDataDsaDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecNssKeyDataDsaDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); + +static xmlSecKeyDataKlass xmlSecNssKeyDataDsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecNssPKIKeyDataSize, + + /* data */ + xmlSecNameDSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefDSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeDSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecNssKeyDataDsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecNssKeyDataDsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecNssKeyDataDsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecNssKeyDataDsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecNssKeyDataDsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecNssKeyDataDsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecNssKeyDataDsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecNssKeyDataDsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecNssKeyDataDsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecNssKeyDataDsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeyDataDsaGetKlass: + * + * The DSA key data klass. + * + * Returns: pointer to DSA key data klass. + */ +xmlSecKeyDataId +xmlSecNssKeyDataDsaGetKlass(void) { + return(&xmlSecNssKeyDataDsaKlass); +} + + +static int +xmlSecNssKeyDataDsaInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId), -1); + + return(xmlSecNssPKIKeyDataInitialize(data)); +} + +static int +xmlSecNssKeyDataDsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecNssKeyDataDsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecNssKeyDataDsaId), -1); + + return(xmlSecNssPKIKeyDataDuplicate(dst, src)); +} + +static void +xmlSecNssKeyDataDsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId)); + + xmlSecNssPKIKeyDataFinalize(data); +} + +static int +xmlSecNssKeyDataDsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data = NULL; + xmlNodePtr cur; + int ret; + PK11SlotInfo *slot = NULL; + CK_OBJECT_HANDLE handle; + SECKEYPublicKey *pubkey=NULL; + PRArenaPool *arena = NULL; + + + xmlSecAssert2(id == xmlSecNssKeyDataDsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + if(xmlSecKeyGetValue(key) != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + ret = -1; + goto done; + } + + slot = PK11_GetBestSlot(CKM_DSA, NULL); + if(slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PK11_GetBestSlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + ret = -1; + goto done; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if(arena == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PORT_NewArena", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + ret = -1; + goto done; + } + + pubkey = (SECKEYPublicKey *)PORT_ArenaZAlloc(arena, + sizeof(SECKEYPublicKey)); + if(pubkey == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PORT_ArenaZAlloc", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + PORT_FreeArena(arena, PR_FALSE); + ret = -1; + goto done; + } + pubkey->arena = arena; + pubkey->u.dsa.params.arena = arena; + pubkey->keyType = dsaKey; + + cur = xmlSecGetNextElementNode(node->children); + + /* first is P node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAP, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.dsa.params.prime)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + ret = -1; + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is Q node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAQ, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.dsa.params.subPrime)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + ret = -1; + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is G node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAG, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.dsa.params.base)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + ret = -1; + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAX, xmlSecNs))) { + /* next is X node. It is REQUIRED for private key but + * NSS does not support it, we just ignore it */ + + cur = xmlSecGetNextElementNode(cur->next); + } + + /* next is Y node. */ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAY, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.dsa.publicValue)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", xmlSecErrorsSafeString(xmlSecNodeDSAY)); + ret = -1; + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* todo: add support for J */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAJ, xmlSecDSigNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* todo: add support for seed */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSASeed, xmlSecDSigNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* todo: add support for pgencounter */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAPgenCounter, xmlSecDSigNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + ret = -1; + goto done; + } + + handle = PK11_ImportPublicKey(slot, pubkey, PR_FALSE); + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + ret = -1; + goto done; + } + + ret = xmlSecNssPKIKeyDataAdoptKey(data, NULL, pubkey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssPKIKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + pubkey = NULL; + + ret = xmlSecKeySetValue(key, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + data = NULL; + + ret = 0; + +done: + if (slot != NULL) { + PK11_FreeSlot(slot); + } + if (ret != 0) { + if (pubkey != NULL) { + SECKEY_DestroyPublicKey(pubkey); + } + if (data != NULL) { + xmlSecKeyDataDestroy(data); + } + } + return(ret); +} + +static int +xmlSecNssKeyDataDsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecNssPKIKeyDataCtxPtr ctx; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecNssKeyDataDsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecNssKeyDataDsaId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + ctx = xmlSecNssPKIKeyDataGetCtx(xmlSecKeyGetValue(key)); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == dsaKey, -1); + + if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) { + /* we can have only private key or public key */ + return(0); + } + + /* first is P node */ + cur = xmlSecAddChild(node, xmlSecNodeDSAP, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.dsa.params.prime), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + return(-1); + } + + /* next is Q node. */ + cur = xmlSecAddChild(node, xmlSecNodeDSAQ, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.dsa.params.subPrime), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + return(-1); + } + + /* next is G node. */ + cur = xmlSecAddChild(node, xmlSecNodeDSAG, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.dsa.params.base), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + return(-1); + } + + /* next is X node: not supported in NSS */ + + /* next is Y node. */ + cur = xmlSecAddChild(node, xmlSecNodeDSAY, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.dsa.publicValue), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + return(-1); + } + + return(0); +} + +static int +xmlSecNssKeyDataDsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + PQGParams *pqgParams = NULL; + PQGVerify *pqgVerify = NULL; + SECStatus rv; + SECStatus res; + PK11SlotInfo *slot = NULL; + SECKEYPrivateKey *privkey = NULL; + SECKEYPublicKey *pubkey = NULL; + int ret = -1; + int j; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId), -1); + xmlSecAssert2(sizeBits > 0, -1); + + j = PQG_PBITS_TO_INDEX(sizeBits); + rv = PK11_PQG_ParamGen(j, &pqgParams, &pqgVerify); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "PK11_PQG_ParamGen", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", sizeBits); + goto done; + } + + rv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &res); + if (rv != SECSuccess || res != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "PK11_PQG_VerifyParams", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", sizeBits); + goto done; + } + + slot = PK11_GetBestSlot(CKM_DSA_KEY_PAIR_GEN, NULL); + PK11_Authenticate(slot, PR_TRUE, NULL /* default pwd callback */); + privkey = PK11_GenerateKeyPair(slot, CKM_DSA_KEY_PAIR_GEN, pqgParams, + &pubkey, PR_FALSE, PR_TRUE, NULL); + + if((privkey == NULL) || (pubkey == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "PK11_GenerateKeyPair", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + goto done; + } + + ret = xmlSecNssPKIKeyDataAdoptKey(data, privkey, pubkey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssPKIKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = 0; + +done: + if (slot != NULL) { + PK11_FreeSlot(slot); + } + if (pqgParams != NULL) { + PK11_PQG_DestroyParams(pqgParams); + } + if (pqgVerify != NULL) { + PK11_PQG_DestroyVerify(pqgVerify); + } + if (ret == 0) { + return (0); + } + if (pubkey != NULL) { + SECKEY_DestroyPublicKey(pubkey); + } + if (privkey != NULL) { + SECKEY_DestroyPrivateKey(privkey); + } + return(-1); +} + +static xmlSecKeyDataType +xmlSecNssKeyDataDsaGetType(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId), xmlSecKeyDataTypeUnknown); + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == dsaKey, -1); + if (ctx->privkey != NULL) { + return(xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); + } else { + return(xmlSecKeyDataTypePublic); + } + + return(xmlSecKeyDataTypeUnknown); +} + +static xmlSecSize +xmlSecNssKeyDataDsaGetSize(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId), 0); + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == dsaKey, -1); + + return(8 * SECKEY_PublicKeyStrength(ctx->pubkey)); +} + +static void +xmlSecNssKeyDataDsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== dsa key: size = %d\n", + xmlSecNssKeyDataDsaGetSize(data)); +} + +static void +xmlSecNssKeyDataDsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<DSAKeyValue size=\"%d\" />\n", + xmlSecNssKeyDataDsaGetSize(data)); +} + +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA +/************************************************************************** + * + * <dsig:RSAKeyValue> processing + * + * http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue + * The RSAKeyValue Element + * + * RSA key values have two fields: Modulus and Exponent. + * + * <RSAKeyValue> + * <Modulus>xA7SEU+e0yQH5rm9kbCDN9o3aPIo7HbP7tX6WOocLZAtNfyxSZDU16ksL6W + * jubafOqNEpcwR3RdFsT7bCqnXPBe5ELh5u4VEy19MzxkXRgrMvavzyBpVRgBUwUlV + * 5foK5hhmbktQhyNdy/6LpQRhDUDsTvK+g9Ucj47es9AQJ3U= + * </Modulus> + * <Exponent>AQAB</Exponent> + * </RSAKeyValue> + * + * Arbitrary-length integers (e.g. "bignums" such as RSA moduli) are + * represented in XML as octet strings as defined by the ds:CryptoBinary type. + * + * Schema Definition: + * + * <element name="RSAKeyValue" type="ds:RSAKeyValueType"/> + * <complexType name="RSAKeyValueType"> + * <sequence> + * <element name="Modulus" type="ds:CryptoBinary"/> + * <element name="Exponent" type="ds:CryptoBinary"/> + * </sequence> + * </complexType> + * + * DTD Definition: + * + * <!ELEMENT RSAKeyValue (Modulus, Exponent) > + * <!ELEMENT Modulus (#PCDATA) > + * <!ELEMENT Exponent (#PCDATA) > + * + * ============================================================================ + * + * To support reading/writing private keys an PrivateExponent element is added + * to the end + * + *************************************************************************/ + +static int xmlSecNssKeyDataRsaInitialize (xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataRsaDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecNssKeyDataRsaFinalize (xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataRsaXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssKeyDataRsaXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssKeyDataRsaGenerate (xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecNssKeyDataRsaGetType (xmlSecKeyDataPtr data); +static xmlSecSize xmlSecNssKeyDataRsaGetSize (xmlSecKeyDataPtr data); +static void xmlSecNssKeyDataRsaDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecNssKeyDataRsaDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); + +static xmlSecKeyDataKlass xmlSecNssKeyDataRsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecNssPKIKeyDataSize, + + /* data */ + xmlSecNameRSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefRSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeRSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecNssKeyDataRsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecNssKeyDataRsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecNssKeyDataRsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecNssKeyDataRsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecNssKeyDataRsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecNssKeyDataRsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecNssKeyDataRsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecNssKeyDataRsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecNssKeyDataRsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecNssKeyDataRsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeyDataRsaGetKlass: + * + * The RSA key data klass. + * + * Returns: pointer to RSA key data klass. + */ +xmlSecKeyDataId +xmlSecNssKeyDataRsaGetKlass(void) { + return(&xmlSecNssKeyDataRsaKlass); +} + +static int +xmlSecNssKeyDataRsaInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId), -1); + + return(xmlSecNssPKIKeyDataInitialize(data)); +} + +static int +xmlSecNssKeyDataRsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecNssKeyDataRsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecNssKeyDataRsaId), -1); + + return(xmlSecNssPKIKeyDataDuplicate(dst, src)); +} + +static void +xmlSecNssKeyDataRsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId)); + + xmlSecNssPKIKeyDataFinalize(data); +} + +static int +xmlSecNssKeyDataRsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data = NULL; + xmlNodePtr cur; + int ret; + PK11SlotInfo *slot = NULL; + SECKEYPublicKey *pubkey=NULL; + PRArenaPool *arena = NULL; + + xmlSecAssert2(id == xmlSecNssKeyDataRsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + if(xmlSecKeyGetValue(key) != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA, + "key already has a value"); + ret = -1; + goto done; + } + + slot = PK11_GetBestSlot(CKM_RSA_PKCS, NULL); + if(slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PK11_GetBestSlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + ret = -1; + goto done; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if(arena == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PORT_NewArena", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + ret = -1; + goto done; + } + + pubkey = (SECKEYPublicKey *)PORT_ArenaZAlloc(arena, + sizeof(SECKEYPublicKey)); + if(pubkey == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PORT_ArenaZAlloc", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + PORT_FreeArena(arena, PR_FALSE); + ret = -1; + goto done; + } + pubkey->arena = arena; + pubkey->keyType = rsaKey; + + cur = xmlSecGetNextElementNode(node->children); + + /* first is Modulus node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRSAModulus, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.rsa.modulus)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + ret = -1; + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is Exponent node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRSAExponent, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.rsa.publicExponent)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + ret = -1; + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeRSAPrivateExponent, xmlSecNs))) { + /* next is X node. It is REQUIRED for private key but + * NSS does not support it. We just ignore it */ + cur = xmlSecGetNextElementNode(cur->next); + } + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "no nodes expected"); + ret = -1; + goto done; + } + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + ret = -1; + goto done; + } + + ret = xmlSecNssPKIKeyDataAdoptKey(data, NULL, pubkey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssPKIKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + goto done; + } + pubkey = NULL; + + ret = xmlSecKeySetValue(key, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + goto done; + } + data = NULL; + + ret = 0; + +done: + if (slot != 0) { + PK11_FreeSlot(slot); + } + if (ret != 0) { + if (pubkey != 0) { + SECKEY_DestroyPublicKey(pubkey); + } + if (data != 0) { + xmlSecKeyDataDestroy(data); + } + } + return(ret); +} + +static int +xmlSecNssKeyDataRsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecNssPKIKeyDataCtxPtr ctx; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecNssKeyDataRsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecNssKeyDataRsaId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + ctx = xmlSecNssPKIKeyDataGetCtx(xmlSecKeyGetValue(key)); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == rsaKey, -1); + + + if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) { + /* we can have only private key or public key */ + return(0); + } + + /* first is Modulus node */ + cur = xmlSecAddChild(node, xmlSecNodeRSAModulus, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.rsa.modulus), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + return(-1); + } + + /* next is Exponent node. */ + cur = xmlSecAddChild(node, xmlSecNodeRSAExponent, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.rsa.publicExponent), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + return(-1); + } + + /* next is PrivateExponent node: not supported in NSS */ + + return(0); +} + +static int +xmlSecNssKeyDataRsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + PK11RSAGenParams params; + PK11SlotInfo *slot = NULL; + SECKEYPrivateKey *privkey = NULL; + SECKEYPublicKey *pubkey = NULL; + int ret = -1; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId), -1); + xmlSecAssert2(sizeBits > 0, -1); + + params.keySizeInBits = sizeBits; + params.pe = 65537; + + slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN, NULL); + PK11_Authenticate(slot, PR_TRUE, NULL /* default pwd callback */); + privkey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, ¶ms, + &pubkey, PR_FALSE, PR_TRUE, NULL); + + if(privkey == NULL || pubkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "PK11_GenerateKeyPair", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + + goto done; + } + + ret = xmlSecNssPKIKeyDataAdoptKey(data, privkey, pubkey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssPKIKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = 0; + +done: + if (slot != NULL) { + PK11_FreeSlot(slot); + } + if (ret == 0) { + return (0); + } + + if (pubkey != NULL) { + SECKEY_DestroyPublicKey(pubkey); + } + if (privkey != NULL) { + SECKEY_DestroyPrivateKey(privkey); + } + return(-1); +} + +static xmlSecKeyDataType +xmlSecNssKeyDataRsaGetType(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId), xmlSecKeyDataTypeUnknown); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->pubkey == NULL || SECKEY_GetPublicKeyType(ctx->pubkey) == rsaKey, -1); + if (ctx->privkey != NULL) { + return(xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); + } else { + return(xmlSecKeyDataTypePublic); + } + + return(xmlSecKeyDataTypeUnknown); +} + +static xmlSecSize +xmlSecNssKeyDataRsaGetSize(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId), 0); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == rsaKey, -1); + + return(8 * SECKEY_PublicKeyStrength(ctx->pubkey)); +} + +static void +xmlSecNssKeyDataRsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== rsa key: size = %d\n", + xmlSecNssKeyDataRsaGetSize(data)); +} + +static void +xmlSecNssKeyDataRsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<RSAKeyValue size=\"%d\" />\n", + xmlSecNssKeyDataRsaGetSize(data)); +} + +#endif /* XMLSEC_NO_RSA */ + + + |