michael@0: /* -*- Mode: C; tab-width: 8 -*-*/ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * This file will implement the functions related to key recovery in michael@0: * CMMF michael@0: */ michael@0: michael@0: #include "cmmf.h" michael@0: #include "cmmfi.h" michael@0: #include "secitem.h" michael@0: #include "keyhi.h" michael@0: michael@0: CMMFKeyRecRepContent* michael@0: CMMF_CreateKeyRecRepContent(void) michael@0: { michael@0: PLArenaPool *poolp; michael@0: CMMFKeyRecRepContent *keyRecContent; michael@0: michael@0: poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); michael@0: if (poolp == NULL) { michael@0: return NULL; michael@0: } michael@0: keyRecContent = PORT_ArenaZNew(poolp, CMMFKeyRecRepContent); michael@0: if (keyRecContent == NULL) { michael@0: PORT_FreeArena(poolp, PR_FALSE); michael@0: return NULL; michael@0: } michael@0: keyRecContent->poolp = poolp; michael@0: return keyRecContent; michael@0: } michael@0: michael@0: SECStatus michael@0: CMMF_DestroyKeyRecRepContent(CMMFKeyRecRepContent *inKeyRecRep) michael@0: { michael@0: PORT_Assert(inKeyRecRep != NULL); michael@0: if (inKeyRecRep != NULL && inKeyRecRep->poolp != NULL) { michael@0: int i; michael@0: michael@0: if (!inKeyRecRep->isDecoded && inKeyRecRep->newSigCert != NULL) { michael@0: CERT_DestroyCertificate(inKeyRecRep->newSigCert); michael@0: } michael@0: if (inKeyRecRep->caCerts != NULL) { michael@0: for (i=0; inKeyRecRep->caCerts[i] != NULL; i++) { michael@0: CERT_DestroyCertificate(inKeyRecRep->caCerts[i]); michael@0: } michael@0: } michael@0: if (inKeyRecRep->keyPairHist != NULL) { michael@0: for (i=0; inKeyRecRep->keyPairHist[i] != NULL; i++) { michael@0: if (inKeyRecRep->keyPairHist[i]->certOrEncCert.choice == michael@0: cmmfCertificate) { michael@0: CERT_DestroyCertificate(inKeyRecRep->keyPairHist[i]-> michael@0: certOrEncCert.cert.certificate); michael@0: } michael@0: } michael@0: } michael@0: PORT_FreeArena(inKeyRecRep->poolp, PR_TRUE); michael@0: } michael@0: return SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: CMMF_KeyRecRepContentSetPKIStatusInfoStatus(CMMFKeyRecRepContent *inKeyRecRep, michael@0: CMMFPKIStatus inPKIStatus) michael@0: { michael@0: PORT_Assert(inKeyRecRep != NULL && inPKIStatus >= cmmfGranted && michael@0: inPKIStatus < cmmfNumPKIStatus); michael@0: if (inKeyRecRep == NULL) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: return cmmf_PKIStatusInfoSetStatus(&inKeyRecRep->status, michael@0: inKeyRecRep->poolp, michael@0: inPKIStatus); michael@0: } michael@0: michael@0: SECStatus michael@0: CMMF_KeyRecRepContentSetNewSignCert(CMMFKeyRecRepContent *inKeyRecRep, michael@0: CERTCertificate *inNewSignCert) michael@0: { michael@0: PORT_Assert (inKeyRecRep != NULL && inNewSignCert != NULL); michael@0: if (inKeyRecRep == NULL || inNewSignCert == NULL) { michael@0: return SECFailure; michael@0: } michael@0: if (!inKeyRecRep->isDecoded && inKeyRecRep->newSigCert) { michael@0: CERT_DestroyCertificate(inKeyRecRep->newSigCert); michael@0: } michael@0: inKeyRecRep->isDecoded = PR_FALSE; michael@0: inKeyRecRep->newSigCert = CERT_DupCertificate(inNewSignCert); michael@0: return (inKeyRecRep->newSigCert == NULL) ? SECFailure : SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: CMMF_KeyRecRepContentSetCACerts(CMMFKeyRecRepContent *inKeyRecRep, michael@0: CERTCertList *inCACerts) michael@0: { michael@0: SECStatus rv; michael@0: void *mark; michael@0: michael@0: PORT_Assert (inKeyRecRep != NULL && inCACerts != NULL); michael@0: if (inKeyRecRep == NULL || inCACerts == NULL) { michael@0: return SECFailure; michael@0: } michael@0: mark = PORT_ArenaMark(inKeyRecRep->poolp); michael@0: rv = cmmf_ExtractCertsFromList(inCACerts, inKeyRecRep->poolp, michael@0: &inKeyRecRep->caCerts); michael@0: if (rv != SECSuccess) { michael@0: PORT_ArenaRelease(inKeyRecRep->poolp, mark); michael@0: } else { michael@0: PORT_ArenaUnmark(inKeyRecRep->poolp, mark); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: SECStatus michael@0: CMMF_KeyRecRepContentSetCertifiedKeyPair(CMMFKeyRecRepContent *inKeyRecRep, michael@0: CERTCertificate *inCert, michael@0: SECKEYPrivateKey *inPrivKey, michael@0: SECKEYPublicKey *inPubKey) michael@0: { michael@0: CMMFCertifiedKeyPair *keyPair; michael@0: CRMFEncryptedValue *dummy; michael@0: PLArenaPool *poolp; michael@0: void *mark; michael@0: SECStatus rv; michael@0: michael@0: PORT_Assert (inKeyRecRep != NULL && michael@0: inCert != NULL && michael@0: inPrivKey != NULL && michael@0: inPubKey != NULL); michael@0: if (inKeyRecRep == NULL || michael@0: inCert == NULL || michael@0: inPrivKey == NULL || michael@0: inPubKey == NULL) { michael@0: return SECFailure; michael@0: } michael@0: poolp = inKeyRecRep->poolp; michael@0: mark = PORT_ArenaMark(poolp); michael@0: if (inKeyRecRep->keyPairHist == NULL) { michael@0: inKeyRecRep->keyPairHist = PORT_ArenaNewArray(poolp, michael@0: CMMFCertifiedKeyPair*, michael@0: (CMMF_MAX_KEY_PAIRS+1)); michael@0: if (inKeyRecRep->keyPairHist == NULL) { michael@0: goto loser; michael@0: } michael@0: inKeyRecRep->allocKeyPairs = CMMF_MAX_KEY_PAIRS; michael@0: inKeyRecRep->numKeyPairs = 0; michael@0: } michael@0: michael@0: if (inKeyRecRep->allocKeyPairs == inKeyRecRep->numKeyPairs) { michael@0: goto loser; michael@0: } michael@0: michael@0: keyPair = PORT_ArenaZNew(poolp, CMMFCertifiedKeyPair); michael@0: if (keyPair == NULL) { michael@0: goto loser; michael@0: } michael@0: rv = cmmf_CertOrEncCertSetCertificate(&keyPair->certOrEncCert, michael@0: poolp, inCert); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: keyPair->privateKey = PORT_ArenaZNew(poolp, CRMFEncryptedValue); michael@0: if (keyPair->privateKey == NULL) { michael@0: goto loser; michael@0: } michael@0: dummy = crmf_create_encrypted_value_wrapped_privkey(inPrivKey, inPubKey, michael@0: keyPair->privateKey); michael@0: PORT_Assert(dummy == keyPair->privateKey); michael@0: if (dummy != keyPair->privateKey) { michael@0: crmf_destroy_encrypted_value(dummy, PR_TRUE); michael@0: goto loser; michael@0: } michael@0: inKeyRecRep->keyPairHist[inKeyRecRep->numKeyPairs] = keyPair; michael@0: inKeyRecRep->numKeyPairs++; michael@0: inKeyRecRep->keyPairHist[inKeyRecRep->numKeyPairs] = NULL; michael@0: PORT_ArenaUnmark(poolp, mark); michael@0: return SECSuccess; michael@0: michael@0: loser: michael@0: PORT_ArenaRelease(poolp, mark); michael@0: return SECFailure; michael@0: } michael@0: michael@0: CMMFPKIStatus michael@0: CMMF_KeyRecRepContentGetPKIStatusInfoStatus(CMMFKeyRecRepContent *inKeyRecRep) michael@0: { michael@0: PORT_Assert(inKeyRecRep != NULL); michael@0: if (inKeyRecRep == NULL) { michael@0: return cmmfNoPKIStatus; michael@0: } michael@0: return cmmf_PKIStatusInfoGetStatus(&inKeyRecRep->status); michael@0: } michael@0: michael@0: CERTCertificate* michael@0: CMMF_KeyRecRepContentGetNewSignCert(CMMFKeyRecRepContent *inKeyRecRep) michael@0: { michael@0: PORT_Assert(inKeyRecRep != NULL); michael@0: if (inKeyRecRep == NULL || michael@0: inKeyRecRep->newSigCert == NULL) { michael@0: return NULL; michael@0: } michael@0: /* newSigCert may not be a real certificate, it may be a hand decoded michael@0: * cert structure. This code makes sure we hand off a real, fully formed michael@0: * CERTCertificate to the caller. TODO: This should move into the decode michael@0: * portion so that we never wind up with a half formed CERTCertificate michael@0: * here. In this case the call would be to CERT_DupCertificate. michael@0: */ michael@0: return CERT_NewTempCertificate(CERT_GetDefaultCertDB(), michael@0: &inKeyRecRep->newSigCert->signatureWrap.data, michael@0: NULL, PR_FALSE, PR_TRUE); michael@0: } michael@0: michael@0: CERTCertList* michael@0: CMMF_KeyRecRepContentGetCACerts(CMMFKeyRecRepContent *inKeyRecRep) michael@0: { michael@0: PORT_Assert(inKeyRecRep != NULL); michael@0: if (inKeyRecRep == NULL || inKeyRecRep->caCerts == NULL) { michael@0: return NULL; michael@0: } michael@0: return cmmf_MakeCertList(inKeyRecRep->caCerts); michael@0: } michael@0: michael@0: int michael@0: CMMF_KeyRecRepContentGetNumKeyPairs(CMMFKeyRecRepContent *inKeyRecRep) michael@0: { michael@0: PORT_Assert(inKeyRecRep != NULL); michael@0: return (inKeyRecRep == NULL) ? 0 : inKeyRecRep->numKeyPairs; michael@0: } michael@0: michael@0: PRBool michael@0: cmmf_KeyRecRepContentIsValidIndex(CMMFKeyRecRepContent *inKeyRecRep, michael@0: int inIndex) michael@0: { michael@0: int numKeyPairs = CMMF_KeyRecRepContentGetNumKeyPairs(inKeyRecRep); michael@0: michael@0: return (PRBool)(inIndex >= 0 && inIndex < numKeyPairs); michael@0: } michael@0: michael@0: CMMFCertifiedKeyPair* michael@0: CMMF_KeyRecRepContentGetCertKeyAtIndex(CMMFKeyRecRepContent *inKeyRecRep, michael@0: int inIndex) michael@0: { michael@0: CMMFCertifiedKeyPair *newKeyPair; michael@0: SECStatus rv; michael@0: michael@0: PORT_Assert(inKeyRecRep != NULL && michael@0: cmmf_KeyRecRepContentIsValidIndex(inKeyRecRep, inIndex)); michael@0: if (inKeyRecRep == NULL || michael@0: !cmmf_KeyRecRepContentIsValidIndex(inKeyRecRep, inIndex)) { michael@0: return NULL; michael@0: } michael@0: newKeyPair = PORT_ZNew(CMMFCertifiedKeyPair); michael@0: if (newKeyPair == NULL) { michael@0: return NULL; michael@0: } michael@0: rv = cmmf_CopyCertifiedKeyPair(NULL, newKeyPair, michael@0: inKeyRecRep->keyPairHist[inIndex]); michael@0: if (rv != SECSuccess) { michael@0: CMMF_DestroyCertifiedKeyPair(newKeyPair); michael@0: newKeyPair = NULL; michael@0: } michael@0: return newKeyPair; michael@0: } michael@0: michael@0: SECStatus michael@0: CMMF_CertifiedKeyPairUnwrapPrivKey(CMMFCertifiedKeyPair *inKeyPair, michael@0: SECKEYPrivateKey *inPrivKey, michael@0: SECItem *inNickName, michael@0: PK11SlotInfo *inSlot, michael@0: CERTCertDBHandle *inCertdb, michael@0: SECKEYPrivateKey **destPrivKey, michael@0: void *wincx) michael@0: { michael@0: CERTCertificate *cert; michael@0: SECItem keyUsageValue = {siBuffer, NULL, 0}; michael@0: unsigned char keyUsage = 0x0; michael@0: SECKEYPublicKey *pubKey; michael@0: SECStatus rv; michael@0: michael@0: PORT_Assert(inKeyPair != NULL && michael@0: inPrivKey != NULL && inCertdb != NULL); michael@0: if (inKeyPair == NULL || michael@0: inPrivKey == NULL || michael@0: inKeyPair->privateKey == NULL || michael@0: inCertdb == NULL) { michael@0: return SECFailure; michael@0: } michael@0: michael@0: cert = CMMF_CertifiedKeyPairGetCertificate(inKeyPair, inCertdb); michael@0: CERT_FindKeyUsageExtension(cert, &keyUsageValue); michael@0: if (keyUsageValue.data != NULL) { michael@0: keyUsage = keyUsageValue.data[3]; michael@0: PORT_Free(keyUsageValue.data); michael@0: } michael@0: pubKey = CERT_ExtractPublicKey(cert); michael@0: rv = crmf_encrypted_value_unwrap_priv_key(NULL, inKeyPair->privateKey, michael@0: inPrivKey, pubKey, michael@0: inNickName, inSlot, keyUsage, michael@0: destPrivKey, wincx); michael@0: SECKEY_DestroyPublicKey(pubKey); michael@0: CERT_DestroyCertificate(cert); michael@0: return rv; michael@0: } michael@0: michael@0: michael@0: PRBool michael@0: CMMF_KeyRecRepContentHasCACerts(CMMFKeyRecRepContent *inKeyRecRep) michael@0: { michael@0: PORT_Assert(inKeyRecRep != NULL); michael@0: if (inKeyRecRep == NULL) { michael@0: return PR_FALSE; michael@0: } michael@0: return (PRBool)(inKeyRecRep->caCerts != NULL && michael@0: inKeyRecRep->caCerts[0] != NULL); michael@0: }