static apr_status_t crypto_digest_final()

in crypto/apr_crypto_nss.c [1466:1603]


static apr_status_t crypto_digest_final(apr_crypto_digest_t *digest)
{
    switch (digest->key->rec->ktype) {

    case APR_CRYPTO_KTYPE_HASH:
    case APR_CRYPTO_KTYPE_HMAC: {

        apr_status_t status = APR_SUCCESS;
        unsigned int len;

        /* first, determine the signature length */
        SECStatus s = PK11_DigestFinal(digest->ctx, NULL, &len, 0);
        if (s != SECSuccess) {
            PRErrorCode perr = PORT_GetError();
            if (perr) {
                digest->f->result->rc = perr;
                digest->f->result->msg = PR_ErrorToName(perr);
            }
            status = APR_ECRYPT;
        }
        else {

            switch (digest->rec->dtype) {
            case APR_CRYPTO_DTYPE_HASH: {

                /* must we allocate the output buffer from a pool? */
                if (!digest->rec->d.hash.s || digest->rec->d.hash.slen != len) {
                    digest->rec->d.hash.slen = len;
                    digest->rec->d.hash.s = apr_palloc(digest->pool, len);
                    if (!digest->rec->d.hash.s) {
                        return APR_ENOMEM;
                    }
                    apr_crypto_clear(digest->pool, digest->rec->d.hash.s, len);
                }

                /* then, determine the signature */
                SECStatus s = PK11_DigestFinal(digest->ctx,
                        digest->rec->d.hash.s, &len, digest->rec->d.hash.slen);
                if (s != SECSuccess) {
                    PRErrorCode perr = PORT_GetError();
                    if (perr) {
                        digest->f->result->rc = perr;
                        digest->f->result->msg = PR_ErrorToName(perr);
                    }
                    status = APR_ECRYPT;
                }

                break;
            }
            case APR_CRYPTO_DTYPE_SIGN: {

                /* must we allocate the output buffer from a pool? */
                if (!digest->rec->d.sign.s || digest->rec->d.sign.slen != len) {
                    digest->rec->d.sign.slen = len;
                    digest->rec->d.sign.s = apr_palloc(digest->pool, len);
                    if (!digest->rec->d.sign.s) {
                        return APR_ENOMEM;
                    }
                    apr_crypto_clear(digest->pool, digest->rec->d.sign.s, len);
                }

                /* then, determine the signature */
                SECStatus s = PK11_DigestFinal(digest->ctx,
                        digest->rec->d.sign.s, &len, digest->rec->d.sign.slen);
                if (s != SECSuccess) {
                    PRErrorCode perr = PORT_GetError();
                    if (perr) {
                        digest->f->result->rc = perr;
                        digest->f->result->msg = PR_ErrorToName(perr);
                    }
                    status = APR_ECRYPT;
                }

                break;
            }
            case APR_CRYPTO_DTYPE_VERIFY: {

                /* must we allocate the output buffer from a pool? */
                if (!digest->rec->d.verify.s
                        || digest->rec->d.verify.slen != len) {
                    digest->rec->d.verify.slen = len;
                    digest->rec->d.verify.s = apr_palloc(digest->pool, len);
                    if (!digest->rec->d.verify.s) {
                        return APR_ENOMEM;
                    }
                    apr_crypto_clear(digest->pool, digest->rec->d.verify.s,
                            len);
                }

                /* then, determine the signature */
                SECStatus s = PK11_DigestFinal(digest->ctx,
                        digest->rec->d.verify.s, &len,
                        digest->rec->d.verify.slen);
                if (s != SECSuccess) {
                    PRErrorCode perr = PORT_GetError();
                    if (perr) {
                        digest->f->result->rc = perr;
                        digest->f->result->msg = PR_ErrorToName(perr);
                    }
                    status = APR_ECRYPT;
                } else if (digest->rec->d.verify.slen
                        == digest->rec->d.verify.vlen) {
                    status =
                            apr_crypto_equals(digest->rec->d.verify.s,
                                    digest->rec->d.verify.v,
                                    digest->rec->d.verify.slen) ?
                            APR_SUCCESS : APR_ENOVERIFY;
                } else {
                    status = APR_ENOVERIFY;
                }

                break;
            }
            default: {
                status = APR_ENODIGEST;
            }
            }

        }

        crypto_digest_cleanup(digest);

        return status;

    }
    case APR_CRYPTO_KTYPE_CMAC: {

        return APR_ENOTIMPL;

    }
    default: {

        return APR_EINVAL;

    }
    }

}