static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
                            size_t *anchors_len)
{
  struct cafile_parser ca;
  br_pem_decoder_context pc;
  br_x509_trust_anchor *ta;
  size_t ta_size;
  br_x509_trust_anchor *new_anchors;
  size_t new_anchors_len;
  br_x509_pkey *pkey;
  FILE *fp;
  unsigned char buf[BUFSIZ], *p;
  const char *name;
  size_t n, i, pushed;

  fp = fopen(path, "rb");
  if(!fp)
    return CURLE_SSL_CACERT_BADFILE;

  ca.err = CURLE_OK;
  ca.in_cert = FALSE;
  ca.anchors = NULL;
  ca.anchors_len = 0;
  br_pem_decoder_init(&pc);
  br_pem_decoder_setdest(&pc, x509_push, &ca);
  for(;;) {
    n = fread(buf, 1, sizeof(buf), fp);
    if(n == 0)
      break;
    p = buf;
    while(n) {
      pushed = br_pem_decoder_push(&pc, p, n);
      if(ca.err)
        goto fail;
      p += pushed;
      n -= pushed;

      switch(br_pem_decoder_event(&pc)) {
      case 0:
        break;
      case BR_PEM_BEGIN_OBJ:
        name = br_pem_decoder_name(&pc);
        if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE"))
          break;
        br_x509_decoder_init(&ca.xc, append_dn, &ca);
        if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) {
          ca.err = CURLE_OUT_OF_MEMORY;
          goto fail;
        }
        new_anchors_len = ca.anchors_len + 1;
        new_anchors = realloc(ca.anchors,
                              new_anchors_len * sizeof(ca.anchors[0]));
        if(!new_anchors) {
          ca.err = CURLE_OUT_OF_MEMORY;
          goto fail;
        }
        ca.anchors = new_anchors;
        ca.anchors_len = new_anchors_len;
        ca.in_cert = TRUE;
        ca.dn_len = 0;
        ta = &ca.anchors[ca.anchors_len - 1];
        ta->dn.data = NULL;
        break;
      case BR_PEM_END_OBJ:
        if(!ca.in_cert)
          break;
        ca.in_cert = FALSE;
        if(br_x509_decoder_last_error(&ca.xc)) {
          ca.err = CURLE_SSL_CACERT_BADFILE;
          goto fail;
        }
        ta->flags = 0;
        if(br_x509_decoder_isCA(&ca.xc))
          ta->flags |= BR_X509_TA_CA;
        pkey = br_x509_decoder_get_pkey(&ca.xc);
        if(!pkey) {
          ca.err = CURLE_SSL_CACERT_BADFILE;
          goto fail;
        }
        ta->pkey = *pkey;

        /* calculate space needed for trust anchor data */
        ta_size = ca.dn_len;
        switch(pkey->key_type) {
        case BR_KEYTYPE_RSA:
          ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen;
          break;
        case BR_KEYTYPE_EC:
          ta_size += pkey->key.ec.qlen;
          break;
        default:
          ca.err = CURLE_FAILED_INIT;
          goto fail;
        }

        /* fill in trust anchor DN and public key data */
        ta->dn.data = malloc(ta_size);
        if(!ta->dn.data) {
          ca.err = CURLE_OUT_OF_MEMORY;
          goto fail;
        }
        memcpy(ta->dn.data, ca.dn, ca.dn_len);
        ta->dn.len = ca.dn_len;
        switch(pkey->key_type) {
        case BR_KEYTYPE_RSA:
          ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len;
          memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen);
          ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen;
          memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen);
          break;
        case BR_KEYTYPE_EC:
          ta->pkey.key.ec.q = ta->dn.data + ta->dn.len;
          memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen);
          break;
        }
        break;
      default:
        ca.err = CURLE_SSL_CACERT_BADFILE;
        goto fail;
      }
    }
  }
  if(ferror(fp))
    ca.err = CURLE_READ_ERROR;

fail:
  fclose(fp);
  if(ca.err == CURLE_OK) {
    *anchors = ca.anchors;
    *anchors_len = ca.anchors_len;
  }
  else {
    for(i = 0; i < ca.anchors_len; ++i)
      free(ca.anchors[i].dn.data);
    free(ca.anchors);
  }

  return ca.err;
}
static CURLcode load_cafile(const char *path, br_x509_trust_anchor **anchors,
                            size_t *anchors_len)
{
  struct cafile_parser ca;
  br_pem_decoder_context pc;
  br_x509_trust_anchor *ta;
  size_t ta_size;
  br_x509_trust_anchor *new_anchors;
  size_t new_anchors_len;
  br_x509_pkey *pkey;
  FILE *fp;
  unsigned char buf[BUFSIZ], *p;
  const char *name;
  size_t n, i, pushed;

  fp = fopen(path, "rb");
  if(!fp)
    return CURLE_SSL_CACERT_BADFILE;

  ca.err = CURLE_OK;
  ca.in_cert = FALSE;
  ca.anchors = NULL;
  ca.anchors_len = 0;
  br_pem_decoder_init(&pc);
  br_pem_decoder_setdest(&pc, x509_push, &ca);
  for(;;) {
    n = fread(buf, 1, sizeof(buf), fp);
    if(n == 0)
      break;
    p = buf;
    while(n) {
      pushed = br_pem_decoder_push(&pc, p, n);
      if(ca.err)
        goto fail;
      p += pushed;
      n -= pushed;

      switch(br_pem_decoder_event(&pc)) {
      case 0:
        break;
      case BR_PEM_BEGIN_OBJ:
        name = br_pem_decoder_name(&pc);
        if(strcmp(name, "CERTIFICATE") && strcmp(name, "X509 CERTIFICATE"))
          break;
        br_x509_decoder_init(&ca.xc, append_dn, &ca);
        if(ca.anchors_len == SIZE_MAX / sizeof(ca.anchors[0])) {
          ca.err = CURLE_OUT_OF_MEMORY;
          goto fail;
        }
        new_anchors_len = ca.anchors_len + 1;
        new_anchors = realloc(ca.anchors,
                              new_anchors_len * sizeof(ca.anchors[0]));
        if(!new_anchors) {
          ca.err = CURLE_OUT_OF_MEMORY;
          goto fail;
        }
        ca.anchors = new_anchors;
        ca.anchors_len = new_anchors_len;
        ca.in_cert = TRUE;
        ca.dn_len = 0;
        ta = &ca.anchors[ca.anchors_len - 1];
        ta->dn.data = NULL;
        break;
      case BR_PEM_END_OBJ:
        if(!ca.in_cert)
          break;
        ca.in_cert = FALSE;
        if(br_x509_decoder_last_error(&ca.xc)) {
          ca.err = CURLE_SSL_CACERT_BADFILE;
          goto fail;
        }
        ta->flags = 0;
        if(br_x509_decoder_isCA(&ca.xc))
          ta->flags |= BR_X509_TA_CA;
        pkey = br_x509_decoder_get_pkey(&ca.xc);
        if(!pkey) {
          ca.err = CURLE_SSL_CACERT_BADFILE;
          goto fail;
        }
        ta->pkey = *pkey;

         
        ta_size = ca.dn_len;
        switch(pkey->key_type) {
        case BR_KEYTYPE_RSA:
          ta_size += pkey->key.rsa.nlen + pkey->key.rsa.elen;
          break;
        case BR_KEYTYPE_EC:
          ta_size += pkey->key.ec.qlen;
          break;
        default:
          ca.err = CURLE_FAILED_INIT;
          goto fail;
        }

         
        ta->dn.data = malloc(ta_size);
        if(!ta->dn.data) {
          ca.err = CURLE_OUT_OF_MEMORY;
          goto fail;
        }
        memcpy(ta->dn.data, ca.dn, ca.dn_len);
        ta->dn.len = ca.dn_len;
        switch(pkey->key_type) {
        case BR_KEYTYPE_RSA:
          ta->pkey.key.rsa.n = ta->dn.data + ta->dn.len;
          memcpy(ta->pkey.key.rsa.n, pkey->key.rsa.n, pkey->key.rsa.nlen);
          ta->pkey.key.rsa.e = ta->pkey.key.rsa.n + ta->pkey.key.rsa.nlen;
          memcpy(ta->pkey.key.rsa.e, pkey->key.rsa.e, pkey->key.rsa.elen);
          break;
        case BR_KEYTYPE_EC:
          ta->pkey.key.ec.q = ta->dn.data + ta->dn.len;
          memcpy(ta->pkey.key.ec.q, pkey->key.ec.q, pkey->key.ec.qlen);
          break;
        }
        break;
      default:
        ca.err = CURLE_SSL_CACERT_BADFILE;
        goto fail;
      }
    }
  }
  if(ferror(fp))
    ca.err = CURLE_READ_ERROR;

fail:
  fclose(fp);
  if(ca.err == CURLE_OK) {
    *anchors = ca.anchors;
    *anchors_len = ca.anchors_len;
  }
  else {
    for(i = 0; i < ca.anchors_len; ++i)
      free(ca.anchors[i].dn.data);
    free(ca.anchors);
  }

  return ca.err;
}