summaryrefslogtreecommitdiff
path: root/security/nss/lib/pk11wrap/pk11skey.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/pk11wrap/pk11skey.c')
-rw-r--r--security/nss/lib/pk11wrap/pk11skey.c80
1 files changed, 67 insertions, 13 deletions
diff --git a/security/nss/lib/pk11wrap/pk11skey.c b/security/nss/lib/pk11wrap/pk11skey.c
index 236fa1e57..e6b6117bd 100644
--- a/security/nss/lib/pk11wrap/pk11skey.c
+++ b/security/nss/lib/pk11wrap/pk11skey.c
@@ -298,17 +298,6 @@ PK11_SymKeyFromHandle(PK11SlotInfo *slot, PK11SymKey *parent, PK11Origin origin,
symKey->origin = origin;
symKey->owner = owner;
- /* adopt the parent's session */
- /* This is only used by SSL. What we really want here is a session
- * structure with a ref count so the session goes away only after all the
- * keys do. */
- if (owner && parent) {
- pk11_CloseSession(symKey->slot, symKey->session,symKey->sessionOwner);
- symKey->sessionOwner = parent->sessionOwner;
- symKey->session = parent->session;
- parent->sessionOwner = PR_FALSE;
- }
-
return symKey;
}
@@ -3243,7 +3232,16 @@ PK11_ExitContextMonitor(PK11Context *cx) {
void
PK11_DestroyContext(PK11Context *context, PRBool freeit)
{
- pk11_CloseSession(context->slot,context->session,context->ownSession);
+ if (context->ownSession && context->key && /* context owns session & key */
+ context->key->session == context->session && /* sharing session */
+ !context->key->sessionOwner) /* sanity check */
+ {
+ /* session still valid, let the key free it as necessary */
+ (void)PK11_Finalize(context); /* end any ongoing activity */
+ context->key->sessionOwner = PR_TRUE;
+ } else {
+ pk11_CloseSession(context->slot,context->session,context->ownSession);
+ }
/* initialize the critical fields of the context */
if (context->savedData != NULL ) PORT_Free(context->savedData);
if (context->key) PK11_FreeSymKey(context->key);
@@ -3427,7 +3425,14 @@ static PK11Context *pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type,
context->operation = operation;
context->key = symKey ? PK11_ReferenceSymKey(symKey) : NULL;
context->slot = PK11_ReferenceSlot(slot);
- context->session = pk11_GetNewSession(slot,&context->ownSession);
+ if (symKey && symKey->sessionOwner) {
+ /* The symkey owns a session. Adopt that session. */
+ context->session = symKey->session;
+ context->ownSession = symKey->sessionOwner;
+ symKey->sessionOwner = PR_FALSE;
+ } else {
+ context->session = pk11_GetNewSession(slot, &context->ownSession);
+ }
context->cx = symKey ? symKey->cx : NULL;
/* get our session */
context->savedData = NULL;
@@ -3647,6 +3652,55 @@ PK11_SaveContext(PK11Context *cx,unsigned char *save,int *len, int saveLength)
return (data != NULL) ? SECSuccess : SECFailure;
}
+/* same as above, but may allocate the return buffer. */
+unsigned char *
+PK11_SaveContextAlloc(PK11Context *cx,
+ unsigned char *preAllocBuf, unsigned int pabLen,
+ unsigned int *stateLen)
+{
+ unsigned char *stateBuf = NULL;
+ unsigned long length = (unsigned long)pabLen;
+ PRBool callerHasBuf = (preAllocBuf != NULL);
+
+ if (cx->ownSession) {
+ PK11_EnterContextMonitor(cx);
+ stateBuf = (unsigned char *)pk11_saveContextHelper(cx, preAllocBuf,
+ &length,
+ callerHasBuf,
+ PR_FALSE);
+ if (stateBuf == NULL && callerHasBuf) {
+ /* pk11_saveContextHelper will attempt to free the supplied
+ * buffer if staticBuffer == PR_FALSE. However, it won't
+ * allocate a new buffer unless staticBuffer == PR_FALSE. We
+ * want to allocate a new buffer if this one isn't big enough,
+ * but we don't want the caller buffer to be freed. So,
+ * we have to try again.
+ */
+ length = 0;
+ stateBuf = (unsigned char *)pk11_saveContextHelper(cx, NULL,
+ &length,
+ PR_FALSE,
+ PR_FALSE);
+ }
+ PK11_ExitContextMonitor(cx);
+ *stateLen = (stateBuf != NULL) ? length : 0;
+ } else {
+ if (pabLen < cx->savedLength) {
+ stateBuf = (unsigned char *)PORT_Alloc(cx->savedLength);
+ if (!stateBuf) {
+ return (unsigned char *)NULL;
+ }
+ } else {
+ stateBuf = preAllocBuf;
+ }
+ if (cx->savedData) {
+ PORT_Memcpy(stateBuf, cx->savedData, cx->savedLength);
+ }
+ *stateLen = cx->savedLength;
+ }
+ return stateBuf;
+}
+
/*
* restore the context state into a new running context. Also required for
* FORTEZZA .