/*
 * FUNCTION: PKIX_PL_CRL_Create (see comments in pkix_pl_pki.h)
 */
PKIX_Error *
PKIX_PL_CRL_Create(
        PKIX_PL_ByteArray *byteArray,
        PKIX_PL_CRL **pCrl,
        void *plContext)
{
        CERTSignedCrl *nssSignedCrl = NULL;
        SECItem derItem, *derCrl = NULL;
        PKIX_PL_CRL *crl = NULL;

        PKIX_ENTER(CRL, "PKIX_PL_CRL_Create");
        PKIX_NULLCHECK_TWO(byteArray, pCrl);

        if (byteArray->length == 0){
            PKIX_ERROR(PKIX_ZEROLENGTHBYTEARRAYFORCRLENCODING);
        }
        derItem.type = siBuffer;
        derItem.data = byteArray->array;
        derItem.len = byteArray->length;
        derCrl = SECITEM_DupItem(&derItem);
        if (!derCrl) {
            PKIX_ERROR(PKIX_ALLOCERROR);
        }
        nssSignedCrl =
            CERT_DecodeDERCrlWithFlags(NULL, derCrl, SEC_CRL_TYPE,
                                       CRL_DECODE_DONT_COPY_DER |
                                       CRL_DECODE_SKIP_ENTRIES);
        if (!nssSignedCrl) {
            PKIX_ERROR(PKIX_CERTDECODEDERCRLFAILED);
        }
        PKIX_CHECK(
            pkix_pl_CRL_CreateWithSignedCRL(nssSignedCrl, derCrl, NULL,
                                            &crl, plContext),
            PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
        nssSignedCrl = NULL;
        derCrl = NULL;
        *pCrl = crl;

cleanup:
        if (derCrl) {
            SECITEM_FreeItem(derCrl, PR_TRUE);
        }
        if (nssSignedCrl) {
            SEC_DestroyCrl(nssSignedCrl);
        } 

        PKIX_RETURN(CRL);
}
/*
 * FUNCTION: pkix_pl_CRL_CreateToList
 * DESCRIPTION:
 *
 *  This function decodes a DER-encoded Certificate Revocation List pointed to
 *  by "derCrlItem", adding the resulting PKIX_PL_CRL, if the decoding was
 *  successful, to the List (possibly empty) pointed to by "crlList".
 *
 * PARAMETERS:
 *  "derCrlItem"
 *      The address of the SECItem containing the DER-encoded Certificate
 *      Revocation List. Must be non-NULL.
 *  "crlList"
 *      The address of the List to which the decoded CRL is added. May be
 *      empty, but must be non-NULL.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a CertStore Error if the function fails in a non-fatal way.
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
 */
PKIX_Error *
pkix_pl_CRL_CreateToList(
    SECItem *derCrlItem,
    PKIX_List *crlList,
    void *plContext)
{
    CERTSignedCrl *nssCrl = NULL;
    PKIX_PL_CRL *crl = NULL;

    PKIX_ENTER(CRL, "pkix_pl_CRL_CreateToList");
    PKIX_NULLCHECK_TWO(derCrlItem, crlList);

    nssCrl = CERT_DecodeDERCrl(NULL, derCrlItem, SEC_CRL_TYPE);
    if (nssCrl == NULL) {
        goto cleanup;
    }

    PKIX_CHECK(pkix_pl_CRL_CreateWithSignedCRL
               (nssCrl, &crl, plContext),
               PKIX_CRLCREATEWITHSIGNEDCRLFAILED);

    nssCrl = NULL;

    PKIX_CHECK(PKIX_List_AppendItem
               (crlList, (PKIX_PL_Object *) crl, plContext),
               PKIX_LISTAPPENDITEMFAILED);

cleanup:
    if (nssCrl) {
        SEC_DestroyCrl(nssCrl);
    }

    PKIX_DECREF(crl);

    PKIX_RETURN(CRL);
}
/*
 * FUNCTION: pkix_pl_LdapCertStore_BuildCrlList
 * DESCRIPTION:
 *
 *  This function takes a List of LdapResponse objects pointed to by
 *  "responseList" and extracts and decodes the CRLs in those responses, storing
 *  the List of those CRLs at "pCrls". If none of the objects can be decoded
 *  into a CRL, the returned List is empty.
 *
 * PARAMETERS:
 *  "responseList"
 *      The address of the List of LdapResponses. Must be non-NULL.
 *  "pCrls"
 *      The address at which the result is stored. Must be non-NULL.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a CertStore Error if the function fails in a non-fatal way.
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
 */
PKIX_Error *
pkix_pl_LdapCertStore_BuildCrlList(
        PKIX_List *responseList,
        PKIX_List **pCrls,
        void *plContext)
{
        PKIX_UInt32 numResponses = 0;
        PKIX_UInt32 respIx = 0;
        LdapAttrMask attrBits = 0;
        CERTSignedCrl *nssCrl = NULL;
        PKIX_PL_LdapResponse *response = NULL;
        PKIX_List *crlList = NULL;
        PKIX_PL_CRL *crl = NULL;
        LDAPMessage *message = NULL;
        LDAPSearchResponseEntry *sre = NULL;
        LDAPSearchResponseAttr **sreAttrArray = NULL;
        LDAPSearchResponseAttr *sreAttr = NULL;
        SECItem *attrType = NULL;
        SECItem **attrVal = NULL;
        SECItem *derCrlCopy = NULL;
        SECItem *derCrlItem = NULL;

        PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_BuildCrlList");
        PKIX_NULLCHECK_TWO(responseList, pCrls);

        PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
                PKIX_LISTCREATEFAILED);

        /* extract crls from response */
        PKIX_CHECK(PKIX_List_GetLength
                (responseList, &numResponses, plContext),
                PKIX_LISTGETLENGTHFAILED);

        for (respIx = 0; respIx < numResponses; respIx++) {
                PKIX_CHECK(PKIX_List_GetItem
                        (responseList,
                        respIx,
                        (PKIX_PL_Object **)&response,
                        plContext),
                        PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(pkix_pl_LdapResponse_GetMessage
                        (response, &message, plContext),
                        PKIX_LDAPRESPONSEGETMESSAGEFAILED);

                sre = &(message->protocolOp.op.searchResponseEntryMsg);
                sreAttrArray = sre->attributes;

                /* Get next element of null-terminated array */
                sreAttr = *sreAttrArray++;
                while (sreAttr != NULL) {
                    attrType = &(sreAttr->attrType);
                    PKIX_CHECK(pkix_pl_LdapRequest_AttrTypeToBit
                        (attrType, &attrBits, plContext),
                        PKIX_LDAPREQUESTATTRTYPETOBITFAILED);
                    /* Is this attrVal a Revocation List? */
                    if (((LDAPATTR_CERTREVLIST | LDAPATTR_AUTHREVLIST) &
                            attrBits) == attrBits) {
                        attrVal = sreAttr->val;
                        derCrlItem = *attrVal++;
                        while (derCrlItem != 0) {
                            /* create a PKIX_PL_Crl from derCrl */
                            derCrlCopy = SECITEM_DupItem(derCrlItem);
                            if (!derCrlCopy) {
                                PKIX_ERROR(PKIX_ALLOCERROR);
                            }
                            /* crl will be based on derCrlCopy, but wont
                             * own the der. */
                            nssCrl =
                                CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy,
                                                       SEC_CRL_TYPE,
                                                       CRL_DECODE_DONT_COPY_DER |
                                                       CRL_DECODE_SKIP_ENTRIES);
                            if (!nssCrl) {
                                SECITEM_FreeItem(derCrlCopy, PKIX_TRUE);
                                continue;
                            }
                            /* pkix crl own the der. */
                            PKIX_CHECK(
                                pkix_pl_CRL_CreateWithSignedCRL(nssCrl, 
                                       derCrlCopy, NULL, &crl, plContext),
                                PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
                            /* Left control over memory pointed by derCrlCopy and
                             * nssCrl to pkix crl. */
                            derCrlCopy = NULL;
                            nssCrl = NULL;
                            PKIX_CHECK(PKIX_List_AppendItem
                                       (crlList, (PKIX_PL_Object *) crl, plContext),
                                       PKIX_LISTAPPENDITEMFAILED);
                            PKIX_DECREF(crl);
                            derCrlItem = *attrVal++;
                        }
                        /* Clean up after PKIX_CHECK_ONLY_FATAL */
                        pkixTempErrorReceived = PKIX_FALSE;
                    }
                    sreAttr = *sreAttrArray++;
                }
                PKIX_DECREF(response);
        }

        *pCrls = crlList;
        crlList = NULL;
cleanup:
        if (derCrlCopy) {
            SECITEM_FreeItem(derCrlCopy, PKIX_TRUE);
        }
        if (nssCrl) {
            SEC_DestroyCrl(nssCrl);
        }
        PKIX_DECREF(crl);
        PKIX_DECREF(crlList);
        PKIX_DECREF(response);

        PKIX_RETURN(CERTSTORE);
}
/*
 * FUNCTION: PKIX_PL_CRL_Create (see comments in pkix_pl_pki.h)
 */
PKIX_Error *
PKIX_PL_CRL_Create(
    PKIX_PL_ByteArray *byteArray,
    PKIX_PL_CRL **pCrl,
    void *plContext)
{
    CERTSignedCrl *nssSignedCrl = NULL;
    SECItem *derCrlItem = NULL;
    void *derBytes = NULL;
    PKIX_UInt32 derLength;
    PKIX_PL_CRL *crl = NULL;

    PKIX_ENTER(CRL, "PKIX_PL_CRL_Create");
    PKIX_NULLCHECK_TWO(byteArray, pCrl);

    PKIX_CHECK(PKIX_PL_ByteArray_GetLength
               (byteArray, &derLength, plContext),
               PKIX_BYTEARRAYGETLENGTHFAILED);

    if (derLength == 0) {
        PKIX_ERROR(PKIX_ZEROLENGTHBYTEARRAYFORCRLENCODING);
    }

    PKIX_CHECK(PKIX_PL_ByteArray_GetPointer
               (byteArray, &derBytes, plContext),
               PKIX_BYTEARRAYGETPOINTERFAILED);

    PKIX_CRL_DEBUG("\t\tCalling SECITEM_AllocItem\n");
    derCrlItem = SECITEM_AllocItem(NULL, NULL, derLength);
    if (derCrlItem == NULL) {
        PKIX_ERROR(PKIX_OUTOFMEMORY);
    }

    PKIX_CRL_DEBUG("\t\tCalling PORT_Memcpy\n");
    (void) PORT_Memcpy(derCrlItem->data, derBytes, derLength);

    PKIX_CRL_DEBUG("\t\tCalling CERT_DecodeDERCrl\n");
    nssSignedCrl = CERT_DecodeDERCrl(NULL, derCrlItem, SEC_CRL_TYPE);
    if (nssSignedCrl == NULL) {
        PKIX_ERROR(PKIX_CERTDECODEDERCRLFAILED);
    }

    PKIX_CHECK(pkix_pl_CRL_CreateWithSignedCRL
               (nssSignedCrl, &crl, plContext),
               PKIX_CRLCREATEWITHSIGNEDCRLFAILED);

    *pCrl = crl;

cleanup:

    if (derCrlItem != NULL) {
        PKIX_CRL_DEBUG("\t\tCalling SECITEM_FreeItem\n");
        SECITEM_FreeItem(derCrlItem, PKIX_TRUE);
        derCrlItem = NULL;
    }

    if (PKIX_ERROR_RECEIVED) {
        if (nssSignedCrl != NULL) {
            PKIX_CRL_DEBUG("\t\tCalling CERT_DestroyCrl\n");
            CERT_DestroyCrl(nssSignedCrl);
            nssSignedCrl = NULL;
        }

        PKIX_DECREF(crl);
    }

    PKIX_FREE(derBytes);

    PKIX_RETURN(CRL);
}