static apr_status_t crypto_digest_final()

in crypto/apr_crypto_commoncrypto.c [1305:1427]


static apr_status_t crypto_digest_final(apr_crypto_digest_t *digest)
{

    switch (digest->key->rec->ktype) {

    case APR_CRYPTO_KTYPE_HASH: {

        size_t len = digest->key->digestSize;

        /* 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);
        }

        switch (digest->key->rec->k.hash.digest) {
        case APR_CRYPTO_DIGEST_MD5:
            CC_MD5_Final(digest->rec->d.hash.s, digest->hash);
            break;
        case APR_CRYPTO_DIGEST_SHA1:
            CC_SHA1_Final(digest->rec->d.hash.s, digest->hash);
            break;
        case APR_CRYPTO_DIGEST_SHA224:
            CC_SHA224_Final(digest->rec->d.hash.s, digest->hash);
            break;
        case APR_CRYPTO_DIGEST_SHA256:
            CC_SHA256_Final(digest->rec->d.hash.s, digest->hash);
            break;
        case APR_CRYPTO_DIGEST_SHA384:
            CC_SHA384_Final(digest->rec->d.hash.s, digest->hash);
            break;
        case APR_CRYPTO_DIGEST_SHA512:
            CC_SHA512_Final(digest->rec->d.hash.s, digest->hash);
            break;
        default:
            return APR_ENODIGEST;
        }

        break;
    }
    case APR_CRYPTO_KTYPE_HMAC: {

        apr_status_t status = APR_SUCCESS;

        size_t len = digest->key->digestSize;

        switch (digest->rec->dtype) {
        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 */
            CCHmacFinal(digest->hmac, digest->rec->d.sign.s);

            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 */
            CCHmacFinal(digest->hmac, digest->rec->d.verify.s);

            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;
            break;
        }
        }

        return status;

    }

    case APR_CRYPTO_KTYPE_CMAC: {

        return APR_ENOTIMPL;

    }

    default: {

        return APR_EINVAL;

    }
    }

    return APR_SUCCESS;
}