ksba_ocsp_prepare_request (ksba_ocsp_t ocsp)
{
  gpg_error_t err;
  struct ocsp_reqitem_s *ri;
  unsigned char *p;
  const unsigned char *der;
  size_t derlen;
  ksba_writer_t w1 = NULL;
  ksba_writer_t w2 = NULL;
  ksba_writer_t w3 = NULL;
  ksba_writer_t w4, w5, w6, w7; /* Used as aliases. */

  if (!ocsp)
    return gpg_error (GPG_ERR_INV_VALUE);

  xfree (ocsp->request_buffer);
  ocsp->request_buffer = NULL;
  ocsp->request_buflen = 0;

  if (!ocsp->requestlist)
    return gpg_error (GPG_ERR_MISSING_ACTION);

  /* Create three writer objects for construction of the request. */
  err = ksba_writer_new (&w3);
  if (!err)
    err = ksba_writer_set_mem (w3, 2048);
  if (!err)
    err = ksba_writer_new (&w2);
  if (!err)
    err = ksba_writer_new (&w1);
  if (err)
    goto leave;


  /* Loop over all single requests. */
  for (ri=ocsp->requestlist; ri; ri = ri->next)
    {
      err = ksba_writer_set_mem (w2, 256);
      if (!err)
        err = ksba_writer_set_mem (w1, 256);
      if (err)
        goto leave;

      /* Write the AlgorithmIdentifier. */
      err = _ksba_der_write_algorithm_identifier (w1, oidstr_sha1, NULL, 0);
      if (err)
        goto leave;

      /* Compute the issuerNameHash and write it into the CertID object. */
      err = issuer_name_hash (ri->issuer_cert, ri->issuer_name_hash);
      if (!err)
        err = _ksba_ber_write_tl (w1, TYPE_OCTET_STRING, CLASS_UNIVERSAL, 0,20);
      if (!err)
        err = ksba_writer_write (w1, ri->issuer_name_hash, 20);
      if(err)
        goto leave;

      /* Compute the issuerKeyHash and write it. */
      err = issuer_key_hash (ri->issuer_cert, ri->issuer_key_hash);
      if (!err)
        err = _ksba_ber_write_tl (w1, TYPE_OCTET_STRING, CLASS_UNIVERSAL, 0,20);
      if (!err)
        err = ksba_writer_write (w1, ri->issuer_key_hash, 20);
      if (err)
        goto leave;

      /* Write the serialNumber of the certificate to be checked. */
      err = _ksba_cert_get_serial_ptr (ri->cert, &der, &derlen);
      if (!err)
        err = _ksba_ber_write_tl (w1, TYPE_INTEGER, CLASS_UNIVERSAL, 0, derlen);
      if (!err)
        err = ksba_writer_write (w1, der, derlen);
      if (err)
        goto leave;
      xfree (ri->serialno);
      ri->serialno = xtrymalloc (derlen);
      if (!ri->serialno)
        err = gpg_error_from_errno (errno);
      if (err)
        goto leave;
      memcpy (ri->serialno, der, derlen);
      ri->serialnolen = derlen;


      /* Now write it out as a sequence to the outer certID object. */
      p = ksba_writer_snatch_mem (w1, &derlen);
      if (!p)
        {
          err = ksba_writer_error (w1);
          goto leave;
        }
      err = _ksba_ber_write_tl (w2, TYPE_SEQUENCE, CLASS_UNIVERSAL,
                                1, derlen);
      if (!err)
        err = ksba_writer_write (w2, p, derlen);
      xfree (p); p = NULL;
      if (err)
        goto leave;

      /* Here we would write singleRequestExtensions. */

      /* Now write it out as a sequence to the outer Request object. */
      p = ksba_writer_snatch_mem (w2, &derlen);
      if (!p)
        {
          err = ksba_writer_error (w2);
          goto leave;
        }
      err = _ksba_ber_write_tl (w3, TYPE_SEQUENCE, CLASS_UNIVERSAL,
                                1, derlen);
      if (!err)
        err = ksba_writer_write (w3, p, derlen);
      xfree (p); p = NULL;
      if (err)
        goto leave;

    } /* End of looping over single requests. */

  /* Reuse writers; for clarity, use new names. */
  w4 = w1;
  w5 = w2;
  err = ksba_writer_set_mem (w4, 2048);
  if (!err)
    err = ksba_writer_set_mem (w5, 2048);
  if (err)
    goto leave;

  /* Put a sequence tag before the requestList. */
  p = ksba_writer_snatch_mem (w3, &derlen);
  if (!p)
    {
      err = ksba_writer_error (w3);
      goto leave;
    }
  err = _ksba_ber_write_tl (w4, TYPE_SEQUENCE, CLASS_UNIVERSAL,
                            1, derlen);
  if (!err)
    err = ksba_writer_write (w4, p, derlen);
  xfree (p); p = NULL;
  if (err)
    goto leave;

  /* The requestExtensions go here. */
  err = write_request_extensions (ocsp, w4);

  /* Write the tbsRequest. */

  /* The version is default, thus we don't write it. */

  /* The requesterName would go here. */

  /* Write the requestList. */
  p = ksba_writer_snatch_mem (w4, &derlen);
  if (!p)
    {
      err = ksba_writer_error (w4);
      goto leave;
    }
  err = _ksba_ber_write_tl (w5, TYPE_SEQUENCE, CLASS_UNIVERSAL,
                            1, derlen);
  if (!err)
    err = ksba_writer_write (w5, p, derlen);
  xfree (p); p = NULL;
  if (err)
    goto leave;

  /* Reuse writers; for clarity, use new names. */
  w6 = w3;
  w7 = w4;
  err = ksba_writer_set_mem (w6, 2048);
  if (!err)
    err = ksba_writer_set_mem (w7, 2048);
  if (err)
    goto leave;

  /* Prepend a sequence tag. */
  p = ksba_writer_snatch_mem (w5, &derlen);
  if (!p)
    {
      err = ksba_writer_error (w5);
      goto leave;
    }
  err = _ksba_ber_write_tl (w6, TYPE_SEQUENCE, CLASS_UNIVERSAL,
                            1, derlen);
  if (!err)
    err = ksba_writer_write (w6, p, derlen);
  xfree (p); p = NULL;
  if (err)
    goto leave;

  /* Write the ocspRequest. */

  /* Note that we do not support the optional signature, because this
     saves us one writer object. */

  /* Prepend a sequence tag. */
/*   p = ksba_writer_snatch_mem (w6, &derlen); */
/*   if (!p) */
/*     { */
/*       err = ksba_writer_error (w6); */
/*       goto leave; */
/*     } */
/*   err = _ksba_ber_write_tl (w7, TYPE_SEQUENCE, CLASS_UNIVERSAL, */
/*                             1, derlen); */
/*   if (!err) */
/*     err = ksba_writer_write (w7, p, derlen); */
/*   xfree (p); p = NULL; */
/*   if (err) */
/*     goto leave; */


  /* Read out the entire request. */
  p = ksba_writer_snatch_mem (w6, &derlen);
  if (!p)
    {
      err = ksba_writer_error (w6);
      goto leave;
    }
  ocsp->request_buffer = p;
  ocsp->request_buflen = derlen;
  /* Ready. */

 leave:
  ksba_writer_release (w3);
  ksba_writer_release (w2);
  ksba_writer_release (w1);
  return err;
}

ksba_ocsp_prepare_request (ksba_ocsp_t ocsp)
{
  gpg_error_t err;
  struct ocsp_reqitem_s *ri;
  unsigned char *p;
  const unsigned char *der;
  size_t derlen;
  ksba_writer_t w1 = NULL;
  ksba_writer_t w2 = NULL;
  ksba_writer_t w3 = NULL;
  ksba_writer_t w4, w5, w6, w7; /* Used as aliases. */

  if (!ocsp)
    return gpg_error (GPG_ERR_INV_VALUE);

  xfree (ocsp->request_buffer);
  ocsp->request_buffer = NULL;
  ocsp->request_buflen = 0;

  if (!ocsp->requestlist)
    return gpg_error (GPG_ERR_MISSING_ACTION);

  /* Create three writer objects for construction of the request. */
  err = ksba_writer_new (&w3);
  if (!err)
    err = ksba_writer_set_mem (w3, 2048);
  if (!err)
    err = ksba_writer_new (&w2);
  if (!err)
    err = ksba_writer_new (&w1);
  if (err)
    goto leave;


  /* Loop over all single requests. */
  for (ri=ocsp->requestlist; ri; ri = ri->next)
    {
      err = ksba_writer_set_mem (w2, 256);
      if (!err)
        err = ksba_writer_set_mem (w1, 256);
      if (err)
        goto leave;

      /* Write the AlgorithmIdentifier. */
      err = _ksba_der_write_algorithm_identifier (w1, oidstr_sha1, NULL, 0);
      if (err)
        goto leave;

      /* Compute the issuerNameHash and write it into the CertID object. */
      err = issuer_name_hash (ri->issuer_cert, ri->issuer_name_hash);
      if (!err)
        err = _ksba_ber_write_tl (w1, TYPE_OCTET_STRING, CLASS_UNIVERSAL, 0,20);
      if (!err)
        err = ksba_writer_write (w1, ri->issuer_name_hash, 20);
      if(err)
        goto leave;

      /* Compute the issuerKeyHash and write it. */
      err = issuer_key_hash (ri->issuer_cert, ri->issuer_key_hash);
      if (!err)
        err = _ksba_ber_write_tl (w1, TYPE_OCTET_STRING, CLASS_UNIVERSAL, 0,20);
      if (!err)
        err = ksba_writer_write (w1, ri->issuer_key_hash, 20);
      if (err)
        goto leave;

      /* Write the serialNumber of the certificate to be checked. */
      err = _ksba_cert_get_serial_ptr (ri->cert, &der, &derlen);
      if (!err)
        err = _ksba_ber_write_tl (w1, TYPE_INTEGER, CLASS_UNIVERSAL, 0, derlen);
      if (!err)
        err = ksba_writer_write (w1, der, derlen);
      if (err)
        goto leave;
      xfree (ri->serialno);
      ri->serialno = xtrymalloc (derlen);
      if (!ri->serialno)
        err = gpg_error_from_errno (errno);
      if (err)
        goto leave;
      memcpy (ri->serialno, der, derlen);
      ri->serialnolen = derlen;


      /* Now write it out as a sequence to the outer certID object. */
      p = ksba_writer_snatch_mem (w1, &derlen);
      if (!p)
        {
          err = ksba_writer_error (w1);
          goto leave;
        }
      err = _ksba_ber_write_tl (w2, TYPE_SEQUENCE, CLASS_UNIVERSAL,
                                1, derlen);
      if (!err)
        err = ksba_writer_write (w2, p, derlen);
      xfree (p); p = NULL;
      if (err)
        goto leave;

      /* Here we would write singleRequestExtensions. */

      /* Now write it out as a sequence to the outer Request object. */
      p = ksba_writer_snatch_mem (w2, &derlen);
      if (!p)
        {
          err = ksba_writer_error (w2);
          goto leave;
        }
      err = _ksba_ber_write_tl (w3, TYPE_SEQUENCE, CLASS_UNIVERSAL,
                                1, derlen);
      if (!err)
        err = ksba_writer_write (w3, p, derlen);
      xfree (p); p = NULL;
      if (err)
        goto leave;

    } /* End of looping over single requests. */

  /* Reuse writers; for clarity, use new names. */
  w4 = w1;
  w5 = w2;
  err = ksba_writer_set_mem (w4, 2048);
  if (!err)
    err = ksba_writer_set_mem (w5, 2048);
  if (err)
    goto leave;

  /* Put a sequence tag before the requestList. */
  p = ksba_writer_snatch_mem (w3, &derlen);
  if (!p)
    {
      err = ksba_writer_error (w3);
      goto leave;
    }
  err = _ksba_ber_write_tl (w4, TYPE_SEQUENCE, CLASS_UNIVERSAL,
                            1, derlen);
  if (!err)
    err = ksba_writer_write (w4, p, derlen);
  xfree (p); p = NULL;
  if (err)
    goto leave;

  /* The requestExtensions go here. */
  err = write_request_extensions (ocsp, w4);

  /* Write the tbsRequest. */

  /* The version is default, thus we don't write it. */

  /* The requesterName would go here. */

  /* Write the requestList. */
  p = ksba_writer_snatch_mem (w4, &derlen);
  if (!p)
    {
      err = ksba_writer_error (w4);
      goto leave;
    }
  err = _ksba_ber_write_tl (w5, TYPE_SEQUENCE, CLASS_UNIVERSAL,
                            1, derlen);
  if (!err)
    err = ksba_writer_write (w5, p, derlen);
  xfree (p); p = NULL;
  if (err)
    goto leave;

  /* Reuse writers; for clarity, use new names. */
  w6 = w3;
  w7 = w4;
  err = ksba_writer_set_mem (w6, 2048);
  if (!err)
    err = ksba_writer_set_mem (w7, 2048);
  if (err)
    goto leave;

  /* Prepend a sequence tag. */
  p = ksba_writer_snatch_mem (w5, &derlen);
  if (!p)
    {
      err = ksba_writer_error (w5);
      goto leave;
    }
  err = _ksba_ber_write_tl (w6, TYPE_SEQUENCE, CLASS_UNIVERSAL,
                            1, derlen);
  if (!err)
    err = ksba_writer_write (w6, p, derlen);
  xfree (p); p = NULL;
  if (err)
    goto leave;

  /* Write the ocspRequest. */

  /* Note that we do not support the optional signature, because this
     saves us one writer object. */

  /* Prepend a sequence tag. */
/*   p = ksba_writer_snatch_mem (w6, &derlen); */
/*   if (!p) */
/*     { */
/*       err = ksba_writer_error (w6); */
/*       goto leave; */
/*     } */
/*   err = _ksba_ber_write_tl (w7, TYPE_SEQUENCE, CLASS_UNIVERSAL, */
/*                             1, derlen); */
/*   if (!err) */
/*     err = ksba_writer_write (w7, p, derlen); */
/*   xfree (p); p = NULL; */
/*   if (err) */
/*     goto leave; */


  /* Read out the entire request. */
  p = ksba_writer_snatch_mem (w6, &derlen);
  if (!p)
    {
      err = ksba_writer_error (w6);
      goto leave;
    }
  ocsp->request_buffer = p;
  ocsp->request_buflen = derlen;
  /* Ready. */

 leave:
  ksba_writer_release (w3);
  ksba_writer_release (w2);
  ksba_writer_release (w1);
  return err;
}
