* Apparently, the PK11 lookup checks external tokens first, * while the CERT lookup checks the database first.  If the leaf is * a CA cert, we want to return the copy in the internal database * rather than the copy on the token, so we use the CERT call.  We * use the PK11 call for user certs that aren't expected to be CAs * by the caller. ***************************************************/ if(slot && !leafIsCA) {
***************************************************/ if(slot) {
Java_org_mozilla_jss_CryptoManager_importCertPackageNative    (JNIEnv *env, jobject this, jbyteArray packageArray, jstring nickString,     jboolean noUser, jboolean leafIsCA){    SECItem *derCerts=NULL;    int certi= -1;    SECItem theDerCert;    int numCerts;    jbyte *packageBytes=NULL;    jsize packageLen;    SECStatus status;    int i, userCertFound = 0;    DERCertCollection collection;    CERTCertDBHandle *certdb = CERT_GetDefaultCertDB();    CK_OBJECT_HANDLE keyID;    PK11SlotInfo *slot=NULL;    char *nickChars = NULL;    jobject leafObject=NULL;    CERTIssuerAndSN issuerAndSN;    PRStatus decodeStatus;    SECItem leafSubject;    CERTCertificate *leafCert = NULL;    /***************************************************     * Validate arguments     ***************************************************/    PR_ASSERT( env!=NULL && this!=NULL );    if(packageArray == NULL) {        PR_ASSERT(PR_FALSE);        JSS_throwMsg(env, CERTIFICATE_ENCODING_EXCEPTION,            "Certificate package is NULL");        goto finish;    }    PR_ASSERT(certdb != NULL);    /***************************************************     * Convert package from byte array to jbyte*     ***************************************************/    packageBytes = (*env)->GetByteArrayElements(env, packageArray, NULL);    if(packageBytes == NULL) {        PR_ASSERT( (*env)->ExceptionOccurred(env) );        goto finish;    }    packageLen = (*env)->GetArrayLength(env, packageArray);    /***************************************************     * Decode package with HCL function     ***************************************************/    status = CERT_DecodeCertPackage((char*) packageBytes,                                    (int) packageLen,                                    collect_der_certs,                                    (void*) &collection);    if( status != SECSuccess  || collection.numCerts < 1 ) {        if( (*env)->ExceptionOccurred(env) == NULL) {            JSS_throwMsg(env, CERTIFICATE_ENCODING_EXCEPTION,                "Security library failed to decode certificate package");        }        goto finish;    }    derCerts = collection.derCerts;    numCerts = collection.numCerts;    /***************************************************     * convert nickname to char*     ***************************************************/    if(nickString == NULL) {        nickChars = NULL;    } else {        nickChars = (char*) (*env)->GetStringUTFChars(env, nickString, NULL);    }    /***************************************************     * user cert can be anywhere in the cert chain. loop and find it.     * The point is to find the user cert with keys on the db, then     * treat the other certs in the chain as CA certs to import.     * The real order of the cert chain shouldn't matter, and shouldn't     * be assumed, and the real location of this user cert in the chain,     * if present, shouldn't be assumed either.     ***************************************************/    if (numCerts > 1) {        for (certi=0; certi<numCerts; certi++) {            slot = PK11_KeyForDERCertExists(&derCerts[certi], &keyID, NULL);            if (slot != NULL) { /* found the user cert */                theDerCert = derCerts[certi];                /*certi now indicates the location of our user cert in chain*/                break;            }        } /* end for */        /* (NO_USER_CERT_HANDLING)         Handles the case when the user certificate is not in         the certificate chain.        */        if ((slot == NULL)) { /* same as "noUser = 1" */            /* #397713 */            if (!find_leaf_cert(certdb, derCerts,                    numCerts, &theDerCert))            {                JSS_throwMsg(env, CERTIFICATE_ENCODING_EXCEPTION,                    "Failed to locate leaf certificate in chain");                goto finish;            }        }    } else {/* numCerts <= 1 */        theDerCert = derCerts[0];        certi = 0;    }    /***************************************************     * Create a new cert structure for the leaf cert     ***************************************************/    /* get issuer and serial number of leaf certificate */    decodeStatus = getCertFields(&theDerCert, &issuerAndSN.derIssuer,        &issuerAndSN.serialNumber, &leafSubject);    if( decodeStatus != PR_SUCCESS ) {        JSS_throwMsg(env, CERTIFICATE_ENCODING_EXCEPTION,            "Failed to extract issuer and serial number from certificate");        goto finish;    }    /***************************************************     * Is this a user cert?     ***************************************************/    if(noUser) {        slot = NULL;    } else {        slot = PK11_KeyForDERCertExists(&theDerCert, &keyID, NULL);    }    if( slot == NULL ) {        if( !noUser && !CERT_IsCADERCert(&theDerCert, NULL)) {            /*****************************************             * This isn't a CA cert, but it also doesn't have a matching             * key, so it's supposed to be a user cert but it has failed             * miserably at its calling.             *****************************************/            JSS_throw(env, NO_SUCH_ITEM_ON_TOKEN_EXCEPTION);            goto finish;        }    } else {        /***************************************************         * We have a user cert, import it         ***************************************************/        /***************************************************         * Check for nickname conflicts         ***************************************************/        if( SEC_CertNicknameConflict(nickChars, &leafSubject, certdb))        {            JSS_throw(env, NICKNAME_CONFLICT_EXCEPTION);            goto finish;        }        /***************************************************         * Import this certificate onto its token.         ***************************************************/        PK11_FreeSlot(slot);        slot = PK11_ImportDERCertForKey(&theDerCert, nickChars, NULL);        if( slot == NULL ) {            /* We already checked for this, shouldn't fail here */            if(PR_GetError() == SEC_ERROR_ADDING_CERT) {                PR_ASSERT(PR_FALSE);                JSS_throw(env, NO_SUCH_ITEM_ON_TOKEN_EXCEPTION);            } else {                JSS_throw(env, TOKEN_EXCEPTION);            }            goto finish;        }        if( ! leafIsCA ) {            ++userCertFound;        }    }    /***************************************************     * Now add the rest of the certs (which should all be CAs)     ***************************************************/    if( numCerts-userCertFound>= 1 ) {      if (certi == 0) {        status = CERT_ImportCAChainTrusted(derCerts+userCertFound,                                    numCerts-userCertFound,                                    certUsageUserCertImport);        if(status != SECSuccess) {            JSS_throwMsgPrErr(env, CERTIFICATE_ENCODING_EXCEPTION,                "CERT_ImportCAChainTrusted returned an error");            goto finish;        }      } else if (certi == numCerts) {        status = CERT_ImportCAChainTrusted(derCerts,                                    numCerts-userCertFound,                                    certUsageUserCertImport);        if(status != SECSuccess) {            JSS_throwMsgPrErr(env, CERTIFICATE_ENCODING_EXCEPTION,                "CERT_ImportCAChainTrusted returned an error");            goto finish;        }      } else {        status = CERT_ImportCAChainTrusted(derCerts,                   certi,                   certUsageUserCertImport);        if(status != SECSuccess) {            JSS_throwMsgPrErr(env, CERTIFICATE_ENCODING_EXCEPTION,                "CERT_ImportCAChainTrusted returned an error");            goto finish;        }        status = CERT_ImportCAChainTrusted(derCerts+certi+1,                   numCerts-certi-1,                   certUsageUserCertImport);        if(status != SECSuccess) {            JSS_throwMsgPrErr(env, CERTIFICATE_ENCODING_EXCEPTION,                "CERT_ImportCAChainTrusted returned an error");            goto finish;        }      }    }    /***************************************************     * Now lookup the leaf cert and make it into a Java object.     * Apparently, the PK11 lookup checks external tokens first,     * while the CERT lookup checks the database first.  If the leaf is     * a CA cert, we want to return the copy in the internal database     * rather than the copy on the token, so we use the CERT call.  We     * use the PK11 call for user certs that aren't expected to be CAs     * by the caller.     ***************************************************/    if(slot && !leafIsCA) {        PK11_FreeSlot(slot);        leafCert = PK11_FindCertByIssuerAndSN(&slot, &issuerAndSN, NULL);    } else {        leafCert = CERT_FindCertByIssuerAndSN(certdb, &issuerAndSN);    }    if( leafCert == NULL ) {        JSS_throwMsgPrErr(env, TOKEN_EXCEPTION,            "Failed to find certificate that was just imported");        goto finish;    }    leafObject = JSS_PK11_wrapCert(env, &leafCert);finish:    if(slot!=NULL) {        PK11_FreeSlot(slot);    }    if(derCerts != NULL) {        for(i=0; i < numCerts; i++) {            SECITEM_FreeItem(&derCerts[i], PR_FALSE /*freeit*/);        }        PR_Free(derCerts);    }    if(packageBytes != NULL) {        (*env)->ReleaseByteArrayElements(env, packageArray, packageBytes,                                            JNI_ABORT); /* don't copy back */    }    if(leafCert != NULL) {        CERT_DestroyCertificate(leafCert);    }    return leafObject;}