static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
                                         X509V3_CTX *ctx, const char *value)
{
    STACK_OF(POLICYINFO) *pols;
    char *pstr;
    POLICYINFO *pol;
    ASN1_OBJECT *pobj;
    STACK_OF(CONF_VALUE) *vals = X509V3_parse_list(value);
    CONF_VALUE *cnf;
    const int num = sk_CONF_VALUE_num(vals);
    int i, ia5org;

    if (vals == NULL) {
        X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_X509V3_LIB);
        return NULL;
    }

    pols = sk_POLICYINFO_new_reserve(NULL, num);
    if (pols == NULL) {
        X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
        goto err;
    }

    ia5org = 0;
    for (i = 0; i < num; i++) {
        cnf = sk_CONF_VALUE_value(vals, i);

        if (cnf->value || !cnf->name) {
            X509V3err(X509V3_F_R2I_CERTPOL,
                      X509V3_R_INVALID_POLICY_IDENTIFIER);
            X509V3_conf_err(cnf);
            goto err;
        }
        pstr = cnf->name;
        if (strcmp(pstr, "ia5org") == 0) {
            ia5org = 1;
            continue;
        } else if (*pstr == '@') {
            STACK_OF(CONF_VALUE) *polsect;
            polsect = X509V3_get_section(ctx, pstr + 1);
            if (!polsect) {
                X509V3err(X509V3_F_R2I_CERTPOL, X509V3_R_INVALID_SECTION);

                X509V3_conf_err(cnf);
                goto err;
            }
            pol = policy_section(ctx, polsect, ia5org);
            X509V3_section_free(ctx, polsect);
            if (pol == NULL)
                goto err;
        } else {
            if ((pobj = OBJ_txt2obj(cnf->name, 0)) == NULL) {
                X509V3err(X509V3_F_R2I_CERTPOL,
                          X509V3_R_INVALID_OBJECT_IDENTIFIER);
                X509V3_conf_err(cnf);
                goto err;
            }
            pol = POLICYINFO_new();
            if (pol == NULL) {
                ASN1_OBJECT_free(pobj);
                X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
                goto err;
            }
            pol->policyid = pobj;
        }
        if (!sk_POLICYINFO_push(pols, pol)) {
            POLICYINFO_free(pol);
            X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
            goto err;
        }
    }
    sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
    return pols;
 err:
    sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
    sk_POLICYINFO_pop_free(pols, POLICYINFO_free);
    return NULL;
}
static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method,
                                         X509V3_CTX *ctx, const char *value)
{
    STACK_OF(POLICYINFO) *pols;
    char *pstr;
    POLICYINFO *pol;
    ASN1_OBJECT *pobj;
    STACK_OF(CONF_VALUE) *vals = X509V3_parse_list(value);
    CONF_VALUE *cnf;
    const int num = sk_CONF_VALUE_num(vals);
    int i, ia5org;

    if (vals == NULL) {
        X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_X509V3_LIB);
        return NULL;
    }

    pols = sk_POLICYINFO_new_reserve(NULL, num);
    if (pols == NULL) {
        X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
        goto err;
    }

    ia5org = 0;
    for (i = 0; i < num; i++) {
        cnf = sk_CONF_VALUE_value(vals, i);

        if (cnf->value || !cnf->name) {
            X509V3err(X509V3_F_R2I_CERTPOL,
                      X509V3_R_INVALID_POLICY_IDENTIFIER);
            X509V3_conf_err(cnf);
            goto err;
        }
        pstr = cnf->name;
        if (strcmp(pstr, "ia5org") == 0) {
            ia5org = 1;
            continue;
        } else if (*pstr == '@') {
            STACK_OF(CONF_VALUE) *polsect;
            polsect = X509V3_get_section(ctx, pstr + 1);
            if (!polsect) {
                X509V3err(X509V3_F_R2I_CERTPOL, X509V3_R_INVALID_SECTION);

                X509V3_conf_err(cnf);
                goto err;
            }
            pol = policy_section(ctx, polsect, ia5org);
            X509V3_section_free(ctx, polsect);
            if (pol == NULL)
                goto err;
        } else {
            if ((pobj = OBJ_txt2obj(cnf->name, 0)) == NULL) {
                X509V3err(X509V3_F_R2I_CERTPOL,
                          X509V3_R_INVALID_OBJECT_IDENTIFIER);
                X509V3_conf_err(cnf);
                goto err;
            }
            pol = POLICYINFO_new();
            if (pol == NULL) {
                ASN1_OBJECT_free(pobj);
                X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
                goto err;
            }
            pol->policyid = pobj;
        }
        if (!sk_POLICYINFO_push(pols, pol)) {
            POLICYINFO_free(pol);
            X509V3err(X509V3_F_R2I_CERTPOL, ERR_R_MALLOC_FAILURE);
            goto err;
        }
    }
    sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
    return pols;
 err:
    sk_CONF_VALUE_pop_free(vals, X509V3_conf_free);
    sk_POLICYINFO_pop_free(pols, POLICYINFO_free);
    return NULL;
}