int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
                           RAW_EXTENSION **res, int *al)
{
    PACKET extensions = *packet;
    size_t i = 0, idx;
    int found = 0;
    custom_ext_methods *exts = NULL;
    RAW_EXTENSION *raw_extensions = NULL;

    /*
     * Initialise server side custom extensions. Client side is done during
     * construction of extensions for the ClientHello.
     */
    if ((context & EXT_CLIENT_HELLO) != 0) {
        exts = &s->cert->srv_ext;
        custom_ext_init(&s->cert->srv_ext);
    } else if ((context & EXT_TLS1_2_SERVER_HELLO) != 0) {
        exts = &s->cert->cli_ext;
    }

    raw_extensions = OPENSSL_zalloc((OSSL_NELEM(ext_defs)
                                     + (exts != NULL ? exts->meths_count : 0))
                                     * sizeof(RAW_EXTENSION));
    if (raw_extensions == NULL) {
        *al = SSL_AD_INTERNAL_ERROR;
        SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, ERR_R_MALLOC_FAILURE);
        return 0;
    }

    while (PACKET_remaining(&extensions) > 0) {
        unsigned int type;
        PACKET extension;

        if (!PACKET_get_net_2(&extensions, &type) ||
            !PACKET_get_length_prefixed_2(&extensions, &extension)) {
            SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_BAD_EXTENSION);
            *al = SSL_AD_DECODE_ERROR;
            goto err;
        }
        /*
         * Verify this extension is allowed. We only check duplicates for
         * extensions that we recognise.
         */
        if (!verify_extension(s, context, type, exts, &found, &idx)
                || (found == 1
                    && raw_extensions[idx].present == 1)) {
            SSLerr(SSL_F_TLS_COLLECT_EXTENSIONS, SSL_R_BAD_EXTENSION);
            *al = SSL_AD_ILLEGAL_PARAMETER;
            goto err;
        }
        if (found) {
            raw_extensions[idx].data = extension;
            raw_extensions[idx].present = 1;
            raw_extensions[idx].type = type;
        }
    }

    /*
     * Initialise all known extensions relevant to this context, whether we have
     * found them or not
     */
    for (i = 0; i < OSSL_NELEM(ext_defs); i++) {
        if(ext_defs[i].init_ext != NULL && (ext_defs[i].context & context) != 0
                && extension_is_relevant(s, ext_defs[i].context, context)
                && !ext_defs[i].init_ext(s, context)) {
            *al = SSL_AD_INTERNAL_ERROR;
            goto err;
        }
    }

    *res = raw_extensions;
    return 1;

 err:
    OPENSSL_free(raw_extensions);
    return 0;
}