Пример #1
0
/* nsISimpleEnumerator enumerateKeys (); */
NS_IMETHODIMP
KeyService::EnumerateKeys(nsISimpleEnumerator **_retval)
{
    SECKEYPrivateKeyList *list;
    SECKEYPrivateKeyListNode *node;

    nsCOMArray<nsIKeyPair> keys;
    
    // Retrieve all the private keys
    list = PK11_ListPrivKeysInSlot(mSlot, NULL, NULL);
    if (!list)
        return NS_NewArrayEnumerator(_retval, keys);
    
    // Walk the list
    for (node = PRIVKEY_LIST_HEAD(list); !PRIVKEY_LIST_END(node,list);
         node = PRIVKEY_LIST_NEXT(node)) {
        KeyPair *key = new KeyPair(node->key);
        keys.AppendObject(key);
    }
    
    SECKEY_DestroyPrivateKeyList(list);

    return NS_NewArrayEnumerator(_retval, keys);
}
/*
 * objectType is bitwise-OR of all the object types you want to traverse.
 */
static PRStatus
traverseTokenObjects
    (JNIEnv *env, PK11SlotInfo *slot, TokenObjectTraversalCallback cb,
        int objectTypes, void *data)
{
    PRStatus status = PR_FAILURE;
    JSSTraversalStatus travstat = INIT_TRAVSTAT;
    SECKEYPrivateKeyList* privkList = NULL;
    SECKEYPublicKeyList* pubkList = NULL;
    PK11SymKey *symKey = NULL;
    CERTCertList *certList = NULL;
    SECStatus secstat;

    /*
     * Get all private keys
     */
    if( objectTypes & PRIVKEY ) {
        SECKEYPrivateKeyListNode *node = NULL;

        privkList = PK11_ListPrivKeysInSlot(slot, NULL /*nickname*/,
                            NULL /*wincx*/);
        if( privkList != NULL ) {

            for( node = PRIVKEY_LIST_HEAD(privkList);
                ! PRIVKEY_LIST_END(node, privkList);
                node = PRIVKEY_LIST_NEXT(node) )
            {
                travstat = cb(env, slot, PRIVKEY, (void*) node->key, data);
                if( travstat.status == PR_FAILURE ) {
                    goto finish;
                }
                if( travstat.deleteIt ) {
                    /* Setting "force" to PR_FALSE means that if there is a
                     * matching cert, the key won't be deleted.
                     * If the KeyStore API is being followed, the cert
                     * should have the same nickname as the key. So
                     * both will get deleted when we scan for matching
                     * certs later.
                     */
                    PK11_DeleteTokenPrivateKey(node->key, PR_FALSE /*force*/);
                    node->key = NULL;
                    PR_REMOVE_LINK(&node->links);
                    /* we don't free node because it is allocated from
                     * the list's arena and will get freed when the list
                     * is freed. */
                }
                if( travstat.stopIterating ) {
                    goto stop_early;
                }
            }
        }
    }

    /*
     * Get all symmetric keys
     */
    if(objectTypes & SYMKEY) {
        /* this function returns a chained list of symmetric keys */
        symKey = PK11_ListFixedKeysInSlot(slot, NULL /*nickname*/,
                    NULL/*wincx*/);

        while( symKey != NULL ) {
            PK11SymKey *deadKey;
            travstat = cb(env, slot, SYMKEY, (void*) symKey, data);
            if( travstat.status != PR_SUCCESS ) {
                goto finish;
            }
            if( travstat.deleteIt ) {
                /* this just deletes the PKCS #11 object. The data structure
                 * is NOT deleted. */
                PK11_DeleteTokenSymKey(symKey);
            }
            if( travstat.stopIterating ) {
                goto stop_early;
            }

            deadKey = symKey;
            symKey = PK11_GetNextSymKey(symKey);
            PK11_FreeSymKey(deadKey);
        }
    }

    /*
     * get all public keys
     */
    if( objectTypes & PUBKEY ) {
        SECKEYPublicKeyListNode *node = NULL;

        pubkList = PK11_ListPublicKeysInSlot(slot, NULL /*nickname*/);
        if( pubkList != NULL ) {

            for( node = PUBKEY_LIST_HEAD(pubkList);
                ! PUBKEY_LIST_END(node, pubkList);
                node = PUBKEY_LIST_NEXT(node) )
            {
                if( node->key == NULL ) {
                    /* workaround NSS bug 130699: PK11_ListPublicKeysInSlot
                     * returns NULL if slot contains token symmetric key */
                    continue;
                }
                travstat = cb(env, slot, PUBKEY, (void*) node->key, data);
                if( travstat.status != PR_SUCCESS ) {
                    goto finish;
                }
                if( travstat.deleteIt ) {
                    /* XXX!!!
                     * Workaround for 125408: PK11_DeleteTokenPublic key asserts
                     * Don't delete the public key.

                     * PK11_DeleteTokenPublicKey(node->key);
                     * node->key = NULL;
                     * PR_REMOVE_LINK(&node->links);
                     */
                    /* node is allocated from the list's arena, it will get
                     * freed with the list */
                }
                if( travstat.stopIterating ) {
                    goto stop_early;
                }
            }

            /*
             * XXX!!!
             * Destroy the list before we move on. Why bother, since we'll
             * do it anyway in the finish block? Because of bug 125408.
             * If we delete the cert and private key while traversing certs,
             * we'll delete the public key too, and then we'll crash when
             * we free the same public key while destroying the list.
             */
            SECKEY_DestroyPublicKeyList(pubkList);
            pubkList = NULL;
        }
    }

    /*
     * Get all certs
     */
    if( objectTypes & CERT ) {
        CERTCertListNode *node = NULL;

        certList = PK11_ListCertsInSlot(slot);
        if( certList == NULL ) {
            JSS_throwMsgPrErr(env, TOKEN_EXCEPTION,
                "Failed to list certificates on token");
            goto finish;
        }

        for( node = CERT_LIST_HEAD(certList);
             ! CERT_LIST_END(node, certList);
             node = CERT_LIST_NEXT(node) )
        {
            travstat = cb(env, slot, CERT, (void*) node->cert, data);
            if( travstat.status != PR_SUCCESS ) {
                goto finish;
            }
            if( travstat.deleteIt ) {
                /*
                 * Since, in a KeyStore, certs and private keys go together,
                 * remove the private key too, if there is one.
                 *
                 * The hack here is that PK11_DeleteTokenCertAndKey will
                 * not delete the cert if there is no matching private key.
                 * We want to the cert to be deleted even if the key isn't
                 * there. So we only call that function if we're sure the
                 * key is there. Otherwise we delete the cert directly.
                 */
                SECKEYPrivateKey *privKey = PK11_FindKeyByAnyCert(node->cert, 
                    NULL /*wincx*/);
                PRBool keyPresent = (privKey != NULL);
                SECKEY_DestroyPrivateKey(privKey);
                if( keyPresent ) {
                    PK11_DeleteTokenCertAndKey(node->cert, NULL /*wincx*/);
                } else {
                    SEC_DeletePermCertificate(node->cert);
                }
                PR_REMOVE_LINK(&node->links);
                /* node is allocated from the list's arena, it will get freed
                 * with the list */
            }
            if( travstat.stopIterating ) {
                goto stop_early;
            }
        }
    }

stop_early:
    status = PR_SUCCESS;
finish:
    if( privkList != NULL ) {
        SECKEY_DestroyPrivateKeyList(privkList);
    }
    if( pubkList != NULL ) {
        SECKEY_DestroyPublicKeyList(pubkList);
    }
    while( symKey != NULL ) {
        PK11SymKey *deadKey;
        deadKey = symKey;
        symKey = PK11_GetNextSymKey(symKey);
        PK11_FreeSymKey(deadKey);
    }
    if( certList != NULL ) {
        CERT_DestroyCertList(certList);
    }
    return status;
}