summaryrefslogtreecommitdiff
path: root/security/nss/lib/crmf/cmmfchal.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/crmf/cmmfchal.c')
-rw-r--r--security/nss/lib/crmf/cmmfchal.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/security/nss/lib/crmf/cmmfchal.c b/security/nss/lib/crmf/cmmfchal.c
new file mode 100644
index 0000000000..2fee983c96
--- /dev/null
+++ b/security/nss/lib/crmf/cmmfchal.c
@@ -0,0 +1,289 @@
+/* -*- Mode: C; tab-width: 8 -*-*/
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "cmmf.h"
+#include "cmmfi.h"
+#include "sechash.h"
+#include "genname.h"
+#include "pk11func.h"
+#include "cert.h"
+#include "secitem.h"
+#include "secmod.h"
+#include "keyhi.h"
+
+static int
+cmmf_create_witness_and_challenge(PLArenaPool *poolp,
+ CMMFChallenge *challenge,
+ long inRandom,
+ SECItem *senderDER,
+ SECKEYPublicKey *inPubKey,
+ void *passwdArg)
+{
+ SECItem *encodedRandNum;
+ SECItem encodedRandStr = { siBuffer, NULL, 0 };
+ SECItem *dummy;
+ unsigned char *randHash, *senderHash, *encChal = NULL;
+ unsigned modulusLen = 0;
+ SECStatus rv = SECFailure;
+ CMMFRand randStr = { { siBuffer, NULL, 0 }, { siBuffer, NULL, 0 } };
+ PK11SlotInfo *slot;
+ PK11SymKey *symKey = NULL;
+ CERTSubjectPublicKeyInfo *spki = NULL;
+
+ encodedRandNum = SEC_ASN1EncodeInteger(poolp, &challenge->randomNumber,
+ inRandom);
+ if (!encodedRandNum) {
+ goto loser;
+ }
+ randHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH);
+ senderHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH);
+ if (randHash == NULL) {
+ goto loser;
+ }
+ rv = PK11_HashBuf(SEC_OID_SHA1, randHash, encodedRandNum->data,
+ (PRUint32)encodedRandNum->len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = PK11_HashBuf(SEC_OID_SHA1, senderHash, senderDER->data,
+ (PRUint32)senderDER->len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ challenge->witness.data = randHash;
+ challenge->witness.len = SHA1_LENGTH;
+
+ randStr.integer = *encodedRandNum;
+ randStr.senderHash.data = senderHash;
+ randStr.senderHash.len = SHA1_LENGTH;
+ dummy = SEC_ASN1EncodeItem(NULL, &encodedRandStr, &randStr,
+ CMMFRandTemplate);
+ if (dummy != &encodedRandStr) {
+ rv = SECFailure;
+ goto loser;
+ }
+ /* XXXX Now I have to encrypt encodedRandStr and stash it away. */
+ modulusLen = SECKEY_PublicKeyStrength(inPubKey);
+ encChal = PORT_ArenaNewArray(poolp, unsigned char, modulusLen);
+ if (encChal == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ slot = PK11_GetBestSlotWithAttributes(CKM_RSA_PKCS, CKF_WRAP, 0, passwdArg);
+ if (slot == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ (void)PK11_ImportPublicKey(slot, inPubKey, PR_FALSE);
+ /* In order to properly encrypt the data, we import as a symmetric
+ * key, and then wrap that key. That in essence encrypts the data.
+ * This is the method recommended in the PK11 world in order
+ * to prevent threading issues as well as breaking any other semantics
+ * the PK11 libraries depend on.
+ */
+ symKey = PK11_ImportSymKey(slot, CKM_RSA_PKCS, PK11_OriginGenerated,
+ CKA_VALUE, &encodedRandStr, passwdArg);
+ if (symKey == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ challenge->challenge.data = encChal;
+ challenge->challenge.len = modulusLen;
+ rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, inPubKey, symKey,
+ &challenge->challenge);
+ PK11_FreeSlot(slot);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ rv = SECITEM_CopyItem(poolp, &challenge->senderDER, senderDER);
+ crmf_get_public_value(inPubKey, &challenge->key);
+/* Fall through */
+loser:
+ if (spki != NULL) {
+ SECKEY_DestroySubjectPublicKeyInfo(spki);
+ }
+ if (encodedRandStr.data != NULL) {
+ PORT_Free(encodedRandStr.data);
+ }
+ if (encodedRandNum != NULL) {
+ SECITEM_FreeItem(encodedRandNum, PR_TRUE);
+ }
+ if (symKey != NULL) {
+ PK11_FreeSymKey(symKey);
+ }
+ return rv;
+}
+
+static SECStatus
+cmmf_create_first_challenge(CMMFPOPODecKeyChallContent *challContent,
+ long inRandom,
+ SECItem *senderDER,
+ SECKEYPublicKey *inPubKey,
+ void *passwdArg)
+{
+ SECOidData *oidData;
+ CMMFChallenge *challenge;
+ SECAlgorithmID *algId;
+ PLArenaPool *poolp;
+ SECStatus rv;
+
+ oidData = SECOID_FindOIDByTag(SEC_OID_SHA1);
+ if (oidData == NULL) {
+ return SECFailure;
+ }
+ poolp = challContent->poolp;
+ challenge = PORT_ArenaZNew(poolp, CMMFChallenge);
+ if (challenge == NULL) {
+ return SECFailure;
+ }
+ algId = challenge->owf = PORT_ArenaZNew(poolp, SECAlgorithmID);
+ if (algId == NULL) {
+ return SECFailure;
+ }
+ rv = SECITEM_CopyItem(poolp, &algId->algorithm, &oidData->oid);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ rv = cmmf_create_witness_and_challenge(poolp, challenge, inRandom,
+ senderDER, inPubKey, passwdArg);
+ challContent->challenges[0] = (rv == SECSuccess) ? challenge : NULL;
+ challContent->numChallenges++;
+ return rv;
+}
+
+CMMFPOPODecKeyChallContent *
+CMMF_CreatePOPODecKeyChallContent(void)
+{
+ PLArenaPool *poolp;
+ CMMFPOPODecKeyChallContent *challContent;
+
+ poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ if (poolp == NULL) {
+ return NULL;
+ }
+ challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent);
+ if (challContent == NULL) {
+ PORT_FreeArena(poolp, PR_FALSE);
+ return NULL;
+ }
+ challContent->poolp = poolp;
+ return challContent;
+}
+
+SECStatus
+CMMF_POPODecKeyChallContentSetNextChallenge(CMMFPOPODecKeyChallContent *inDecKeyChall,
+ long inRandom,
+ CERTGeneralName *inSender,
+ SECKEYPublicKey *inPubKey,
+ void *passwdArg)
+{
+ CMMFChallenge *curChallenge;
+ PLArenaPool *genNamePool = NULL, *poolp;
+ SECStatus rv;
+ SECItem *genNameDER;
+ void *mark;
+
+ PORT_Assert(inDecKeyChall != NULL &&
+ inSender != NULL &&
+ inPubKey != NULL);
+
+ if (inDecKeyChall == NULL ||
+ inSender == NULL || inPubKey == NULL) {
+ return SECFailure;
+ }
+ poolp = inDecKeyChall->poolp;
+ mark = PORT_ArenaMark(poolp);
+
+ genNamePool = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
+ genNameDER = CERT_EncodeGeneralName(inSender, NULL, genNamePool);
+ if (genNameDER == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ if (inDecKeyChall->challenges == NULL) {
+ inDecKeyChall->challenges =
+ PORT_ArenaZNewArray(poolp, CMMFChallenge *, (CMMF_MAX_CHALLENGES + 1));
+ inDecKeyChall->numAllocated = CMMF_MAX_CHALLENGES;
+ }
+
+ if (inDecKeyChall->numChallenges >= inDecKeyChall->numAllocated) {
+ rv = SECFailure;
+ goto loser;
+ }
+
+ if (inDecKeyChall->numChallenges == 0) {
+ rv = cmmf_create_first_challenge(inDecKeyChall, inRandom,
+ genNameDER, inPubKey, passwdArg);
+ } else {
+ curChallenge = PORT_ArenaZNew(poolp, CMMFChallenge);
+ if (curChallenge == NULL) {
+ rv = SECFailure;
+ goto loser;
+ }
+ rv = cmmf_create_witness_and_challenge(poolp, curChallenge, inRandom,
+ genNameDER, inPubKey,
+ passwdArg);
+ if (rv == SECSuccess) {
+ inDecKeyChall->challenges[inDecKeyChall->numChallenges] =
+ curChallenge;
+ inDecKeyChall->numChallenges++;
+ }
+ }
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_ArenaUnmark(poolp, mark);
+ PORT_FreeArena(genNamePool, PR_FALSE);
+ return SECSuccess;
+
+loser:
+ PORT_ArenaRelease(poolp, mark);
+ if (genNamePool != NULL) {
+ PORT_FreeArena(genNamePool, PR_FALSE);
+ }
+ PORT_Assert(rv != SECSuccess);
+ return rv;
+}
+
+SECStatus
+CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent *inDecKeyResp)
+{
+ PORT_Assert(inDecKeyResp != NULL);
+ if (inDecKeyResp != NULL && inDecKeyResp->poolp != NULL) {
+ PORT_FreeArena(inDecKeyResp->poolp, PR_FALSE);
+ }
+ return SECSuccess;
+}
+
+int
+CMMF_POPODecKeyRespContentGetNumResponses(CMMFPOPODecKeyRespContent *inRespCont)
+{
+ int numResponses = 0;
+
+ PORT_Assert(inRespCont != NULL);
+ if (inRespCont == NULL) {
+ return 0;
+ }
+
+ while (inRespCont->responses[numResponses] != NULL) {
+ numResponses++;
+ }
+ return numResponses;
+}
+
+SECStatus
+CMMF_POPODecKeyRespContentGetResponse(CMMFPOPODecKeyRespContent *inRespCont,
+ int inIndex,
+ long *inDest)
+{
+ PORT_Assert(inRespCont != NULL);
+
+ if (inRespCont == NULL || inIndex < 0 ||
+ inIndex >= CMMF_POPODecKeyRespContentGetNumResponses(inRespCont)) {
+ return SECFailure;
+ }
+ *inDest = DER_GetInteger(inRespCont->responses[inIndex]);
+ return (*inDest == -1) ? SECFailure : SECSuccess;
+}