Ejemplo n.º 1
0
/* Add the GeneralNames object GNAMES to the list of extensions in CR.
   Use OID as object identifier for the extensions. */
static gpg_error_t
add_general_names_to_extn (ksba_certreq_t cr, struct general_names_s *gnames,
                           const char *oid)
{
  struct general_names_s *g;
  size_t n, n1, n2;
  struct extn_list_s *e;
  unsigned char *der;

  /* Calculate the required size. */
  n1 = 0;
  for (g=gnames; g; g = g->next)
    n1 += g->datalen;

  n2  = _ksba_ber_count_tl (TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n1);
  n2 += n1;

  /* Allocate memory and encode all. */
  e = xtrymalloc (sizeof *e + n2 - 1);
  if (!e)
    return gpg_error_from_errno (errno);
  e->oid = oid;
  e->critical = 0;
  e->derlen = n2;
  der = e->der;
  n = _ksba_ber_encode_tl (der, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n1);
  if (!n)
    return gpg_error (GPG_ERR_BUG); /* (no need to cleanup after a bug) */
  der += n;

  for (g=gnames; g; g = g->next)
    {
      memcpy (der, g->data, g->datalen);
      der += g->datalen;
    }
  assert (der - e->der == n2);

  e->next = cr->extn_list;
  cr->extn_list = e;
  return 0;
}
Ejemplo n.º 2
0
/* Take a public-key S-Exp and convert it into a DER encoded
   publicKeyInfo */
gpg_error_t
_ksba_keyinfo_from_sexp (ksba_const_sexp_t sexp,
                         unsigned char **r_der, size_t *r_derlen)
{
  gpg_error_t err;
  const unsigned char *s;
  char *endp;
  unsigned long n, n1;
  const unsigned char *oid;
  int oidlen;
  unsigned char *curve_oid = NULL;
  size_t curve_oidlen;
  pkalgo_t pkalgo;
  int i;
  struct {
    const char *name;
    int namelen;
    const unsigned char *value;
    int valuelen;
  } parm[10]; 
  int parmidx;
  int idxtbl[10];
  int idxtbllen;
  const char *parmdesc, *algoparmdesc;
  ksba_writer_t writer = NULL;
  void *algoparmseq_value = NULL;
  size_t algoparmseq_len;
  void *bitstr_value = NULL;
  size_t bitstr_len;

  if (!sexp)
    return gpg_error (GPG_ERR_INV_VALUE);

  s = sexp;
  if (*s != '(')
    return gpg_error (GPG_ERR_INV_SEXP);
  s++;

  n = strtoul (s, &endp, 10);
  s = endp;
  if (!n || *s != ':')
    return gpg_error (GPG_ERR_INV_SEXP); /* we don't allow empty lengths */
  s++;
  if (n != 10 || memcmp (s, "public-key", 10))
    return gpg_error (GPG_ERR_UNKNOWN_SEXP);
  s += 10;
  if (*s != '(')
    return gpg_error (digitp (s)? GPG_ERR_UNKNOWN_SEXP : GPG_ERR_INV_SEXP);
  s++;

  /* Break out the algorithm ID */
  n = strtoul (s, &endp, 10);
  s = endp;
  if (!n || *s != ':')
    return gpg_error (GPG_ERR_INV_SEXP); /* we don't allow empty lengths */
  s++;
  oid = oid_from_buffer (s, n, &oidlen, &pkalgo);
  if (!oid)
    return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
  s += n;

  /* Collect all the values */
  for (parmidx = 0; *s != ')' ; parmidx++)
    {
      if (parmidx >= DIM(parm))
        return gpg_error (GPG_ERR_GENERAL);
      if (*s != '(')
        return gpg_error (digitp(s)? GPG_ERR_UNKNOWN_SEXP:GPG_ERR_INV_SEXP);
      s++;
      n = strtoul (s, &endp, 10);
      s = endp;
      if (!n || *s != ':')
        return gpg_error (GPG_ERR_INV_SEXP); 
      s++;
      parm[parmidx].name = s;
      parm[parmidx].namelen = n;
      s += n; 
      if (!digitp(s))
        return gpg_error (GPG_ERR_UNKNOWN_SEXP); /* ... or invalid S-Exp. */

      n = strtoul (s, &endp, 10);
      s = endp;
      if (!n || *s != ':')
        return gpg_error (GPG_ERR_INV_SEXP); 
      s++;
      parm[parmidx].value = s;
      parm[parmidx].valuelen = n;
      s += n;
      if ( *s != ')')
        return gpg_error (GPG_ERR_UNKNOWN_SEXP); /* ... or invalid S-Exp. */
      s++;
    }
  s++;
  /* We need another closing parenthesis. */
  if ( *s != ')' )
    return gpg_error (GPG_ERR_INV_SEXP); 

  /* Describe the parameters in the order we want them and construct
     IDXTBL to access them.  For DSA wie also set algoparmdesc so
     that we can later build the parameters for the
     algorithmIdentifier.  */
  algoparmdesc = NULL;
  switch (pkalgo)
    {
    case PKALGO_RSA: parmdesc = "ne"; break;
    case PKALGO_DSA: parmdesc = "y" ; algoparmdesc = "pqg"; break;
    case PKALGO_ECC: parmdesc = "Cq"; break;
    default: return gpg_error (GPG_ERR_UNKNOWN_ALGORITHM);
    }      

  idxtbllen = 0;
  for (s = parmdesc; *s; s++)
    {
      for (i=0; i < parmidx; i++)
        {
          assert (idxtbllen < DIM (idxtbl));
          switch (*s)
            {
            case 'C': /* Magic value for "curve".  */
              if (parm[i].namelen == 5 && !memcmp (parm[i].name, "curve", 5))
                {
                  idxtbl[idxtbllen++] = i;
                  i = parmidx; /* Break inner loop.  */
                }
              break;
            default:
              if (parm[i].namelen == 1 && parm[i].name[0] == *s)
                {
                  idxtbl[idxtbllen++] = i;
                  i = parmidx; /* Break inner loop.  */
                }
              break;
            }
        }
    }
  if (idxtbllen != strlen (parmdesc))
    return gpg_error (GPG_ERR_UNKNOWN_SEXP);

  if (pkalgo == PKALGO_ECC)
    {
      curve_oid = get_ecc_curve_oid (parm[idxtbl[0]].value,
                                     parm[idxtbl[0]].valuelen,
                                     &curve_oidlen);
      if (!curve_oid)
        return gpg_error (GPG_ERR_UNKNOWN_SEXP);
    }

      
  /* Create write object. */
  err = ksba_writer_new (&writer);
  if (err)
    goto leave;
  err = ksba_writer_set_mem (writer, 1024);
  if (err)
    goto leave;
  
  /* We create the keyinfo in 2 steps:
     
     1. We build the inner one and encapsulate it in a bit string.
  
     2. We create the outer sequence include the algorithm identifier
        and the bit string from step 1. 
   */
  if (pkalgo == PKALGO_ECC)
    {
      /* Write the bit string header and the number of unused bits. */
      err = _ksba_ber_write_tl (writer, TYPE_BIT_STRING, CLASS_UNIVERSAL, 
                                0, parm[idxtbl[1]].valuelen + 1);
      if (!err)
        err = ksba_writer_write (writer, "", 1);
      /* And the actual raw value.  */
      if (!err)
        err = ksba_writer_write (writer, parm[idxtbl[1]].value,
                                 parm[idxtbl[1]].valuelen);
      if (err)
        goto leave;

    }
  else /* RSA and DSA */
    {
      /* Calculate the size of the sequence value and the size of the
         bit string value.  NOt ethat in case there is only one
         integer to write, no sequence is used.  */
      for (n=0, i=0; i < idxtbllen; i++ )
        {
          n += _ksba_ber_count_tl (TYPE_INTEGER, CLASS_UNIVERSAL, 0,
                                   parm[idxtbl[i]].valuelen);
          n += parm[idxtbl[i]].valuelen;
        }
  
      n1 = 1; /* # of unused bits.  */
      if (idxtbllen > 1)
        n1 += _ksba_ber_count_tl (TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
      n1 += n;
  
      /* Write the bit string header and the number of unused bits. */
      err = _ksba_ber_write_tl (writer, TYPE_BIT_STRING, CLASS_UNIVERSAL, 
                                0, n1);
      if (!err)
        err = ksba_writer_write (writer, "", 1);
      if (err)
        goto leave;
      
      /* Write the sequence tag and the integers. */
      if (idxtbllen > 1)
        err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1,n);
      if (err)
        goto leave;
      for (i=0; i < idxtbllen; i++)
        {
          /* fixme: we should make sure that the integer conforms to the
             ASN.1 encoding rules. */
          err  = _ksba_ber_write_tl (writer, TYPE_INTEGER, CLASS_UNIVERSAL, 0, 
                                     parm[idxtbl[i]].valuelen);
          if (!err)
            err = ksba_writer_write (writer, parm[idxtbl[i]].value, 
                                     parm[idxtbl[i]].valuelen);
          if (err)
            goto leave;
        }
    }

  /* Get the encoded bit string. */
  bitstr_value = ksba_writer_snatch_mem (writer, &bitstr_len);
  if (!bitstr_value)
    {
      err = gpg_error (GPG_ERR_ENOMEM);
      goto leave;
    }
  
  /* If the algorithmIdentifier requires a sequence with parameters,
     build them now.  We can reuse the IDXTBL for that.  */
  if (algoparmdesc)
    {
      idxtbllen = 0;
      for (s = algoparmdesc; *s; s++)
        {
          for (i=0; i < parmidx; i++)
            {
              assert (idxtbllen < DIM (idxtbl));
              if (parm[i].namelen == 1 && parm[i].name[0] == *s)
                {
                  idxtbl[idxtbllen++] = i;
                  break;
                }
            }
        }
      if (idxtbllen != strlen (algoparmdesc))
        return gpg_error (GPG_ERR_UNKNOWN_SEXP);

      err = ksba_writer_set_mem (writer, 1024);
      if (err)
        goto leave;

      /* Calculate the size of the sequence.  */
      for (n=0, i=0; i < idxtbllen; i++ )
        {
          n += _ksba_ber_count_tl (TYPE_INTEGER, CLASS_UNIVERSAL, 0,
                                   parm[idxtbl[i]].valuelen);
          n += parm[idxtbl[i]].valuelen;
        }
      //      n += _ksba_ber_count_tl (TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
  
      /* Write the sequence tag followed by the integers. */
      err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
      if (err)
        goto leave;
      for (i=0; i < idxtbllen; i++)
        {
          err = _ksba_ber_write_tl (writer, TYPE_INTEGER, CLASS_UNIVERSAL, 0, 
                                    parm[idxtbl[i]].valuelen);
          if (!err)
            err = ksba_writer_write (writer, parm[idxtbl[i]].value, 
                                     parm[idxtbl[i]].valuelen);
          if (err)
            goto leave;
        }

      /* Get the encoded sequence.  */
      algoparmseq_value = ksba_writer_snatch_mem (writer, &algoparmseq_len);
      if (!algoparmseq_value)
        {
          err = gpg_error (GPG_ERR_ENOMEM);
          goto leave;
        }
    }
  else
    algoparmseq_len = 0;

  /* Reinitialize the buffer to create the outer sequence. */
  err = ksba_writer_set_mem (writer, 1024);
  if (err)
    goto leave;

  /* Calulate lengths. */
  n  = _ksba_ber_count_tl (TYPE_OBJECT_ID, CLASS_UNIVERSAL, 0, oidlen);
  n += oidlen;
  if (algoparmseq_len)
    {
      n += algoparmseq_len;
    }
  else if (pkalgo == PKALGO_ECC)
    {
      n += _ksba_ber_count_tl (TYPE_OBJECT_ID, CLASS_UNIVERSAL,
                               0, curve_oidlen);
      n += curve_oidlen;
    }
  else if (pkalgo == PKALGO_RSA)
    {
      n += _ksba_ber_count_tl (TYPE_NULL, CLASS_UNIVERSAL, 0, 0);
    }

  n1 = n;
  n1 += _ksba_ber_count_tl (TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
  n1 += bitstr_len;

  /* The outer sequence.  */
  err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n1);
  if (err)
    goto leave;

  /* The sequence.  */
  err = _ksba_ber_write_tl (writer, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1, n);
  if (err)
    goto leave;

  /* The object id.  */
  err = _ksba_ber_write_tl (writer, TYPE_OBJECT_ID,CLASS_UNIVERSAL, 0, oidlen);
  if (!err)
    err = ksba_writer_write (writer, oid, oidlen);
  if (err)
    goto leave;

  /* The parameter. */
  if (algoparmseq_len)
    {
      err = ksba_writer_write (writer, algoparmseq_value, algoparmseq_len);
    }
  else if (pkalgo == PKALGO_ECC)
    {
      err = _ksba_ber_write_tl (writer, TYPE_OBJECT_ID, CLASS_UNIVERSAL,
                                0, curve_oidlen);
      if (!err)
        err = ksba_writer_write (writer, curve_oid, curve_oidlen);
    }
  else if (pkalgo == PKALGO_RSA)
    {
      err = _ksba_ber_write_tl (writer, TYPE_NULL, CLASS_UNIVERSAL, 0, 0);
    }
  if (err)
    goto leave;

  /* Append the pre-constructed bit string.  */
  err = ksba_writer_write (writer, bitstr_value, bitstr_len);
  if (err)
    goto leave;
  
  /* Get the result. */
  *r_der = ksba_writer_snatch_mem (writer, r_derlen);
  if (!*r_der)
    err = gpg_error (GPG_ERR_ENOMEM);

 leave:
  ksba_writer_release (writer);
  xfree (bitstr_value);
  xfree (curve_oid);
  return err;
}
Ejemplo n.º 3
0
/* Store the subject's name.  Does perform some syntactic checks on
   the name.  The first added subject is the real one, all subsequent
   calls add subjectAltNames.

   NAME must be a valid RFC-2253 encoded DN name for the first one or an
   email address enclosed in angle brackets for all further calls.
 */
gpg_error_t
ksba_certreq_add_subject (ksba_certreq_t cr, const char *name)
{
  unsigned long namelen;
  size_t n, n1;
  struct general_names_s *gn;
  unsigned char *der;
  int tag;
  const char *endp;

  if (!cr || !name)
    return gpg_error (GPG_ERR_INV_VALUE);
  if (!cr->subject.der)
    return _ksba_dn_from_str (name, &cr->subject.der, &cr->subject.derlen);
  /* This is assumed to be an subjectAltName. */

  /* Note that the way we pass the name should match what
     ksba_cert_get_subject() returns.  In particular we expect that it
     is a real string and thus a canonical S-expression is
     additionally terminated by a 0. */
  namelen = strlen (name);
  if (*name == '<' && name[namelen-1] == '>'
      && namelen >= 4 && strchr (name, '@'))
    {
      name++;
      namelen -= 2;
      tag = 1;  /* rfc822Name */
    }
  else if (!strncmp (name, "(8:dns-name", 11))
    {
      tag = 2; /* dNSName */
      namelen = strtoul (name+11, (char**)&endp, 10);
      name = endp;
      if (!namelen || *name != ':')
        return gpg_error (GPG_ERR_INV_SEXP);
      name++;
    }
  else if (!strncmp (name, "(3:uri", 6))
    {
      tag = 6; /* uRI */
      namelen = strtoul (name+6, (char**)&endp, 10);
      name = endp;
      if (!namelen || *name != ':')
        return gpg_error (GPG_ERR_INV_SEXP);
      name++;
    }
  else
    return gpg_error (GPG_ERR_INV_VALUE);

  n1  = _ksba_ber_count_tl (tag, CLASS_CONTEXT, 0, namelen);
  n1 += namelen;

  gn = xtrymalloc (sizeof *gn + n1 - 1);
  if (!gn)
    return gpg_error_from_errno (errno);
  gn->tag = tag;
  gn->datalen = n1;
  der = (unsigned char *)gn->data;
  n = _ksba_ber_encode_tl (der, tag, CLASS_CONTEXT, 0, namelen);
  if (!n)
    return gpg_error (GPG_ERR_BUG);
  der += n;
  memcpy (der, name, namelen);
  assert (der + namelen - (unsigned char*)gn->data == n1);

  gn->next = cr->subject_alt_names;
  cr->subject_alt_names = gn;

  return 0;
}