Fix use cases of snprintf.
[gnupg.git] / sm / certreqgen.c
index 15fc7a2..4d50270 100644 (file)
@@ -85,6 +85,7 @@ enum para_name
     pNOTAFTER,
     pSIGNINGKEY,
     pHASHALGO,
+    pAUTHKEYID,
     pSUBJKEYID,
     pEXTENSION
   };
@@ -107,6 +108,7 @@ struct reqgen_ctrl_s
 };
 
 
+static const char oidstr_authorityKeyIdentifier[] = "2.5.29.35";
 static const char oidstr_subjectKeyIdentifier[] = "2.5.29.14";
 static const char oidstr_keyUsage[] = "2.5.29.15";
 static const char oidstr_basicConstraints[] = "2.5.29.19";
@@ -247,6 +249,7 @@ read_parameters (ctrl_t ctrl, estream_t fp, estream_t out_fp)
     { "Not-After",      pNOTAFTER },
     { "Signing-Key",    pSIGNINGKEY },
     { "Hash-Algo",      pHASHALGO },
+    { "Authority-Key-Id", pAUTHKEYID },
     { "Subject-Key-Id", pSUBJKEYID },
     { "Extension",      pEXTENSION, 1 },
     { NULL, 0 }
@@ -302,7 +305,7 @@ read_parameters (ctrl_t ctrl, estream_t fp, estream_t out_fp)
               para = NULL;
            }
           else
-            log_info ("skipping control `%s' (%s)\n", keyword, value);
+            log_info ("skipping control '%s' (%s)\n", keyword, value);
 
           continue;
        }
@@ -434,7 +437,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
   char numbuf[20];
   unsigned char keyparms[100];
   int rc = 0;
-  ksba_sexp_t public;
+  ksba_sexp_t public = NULL;
   ksba_sexp_t sigkey = NULL;
   int seq;
   size_t erroff, errlen;
@@ -499,10 +502,10 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
     {
       r = get_parameter (para, pNAMEDN, 0);
       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
-        log_error (_("line %d: invalid subject name label `%.*s'\n"),
+        log_error (_("line %d: invalid subject name label '%.*s'\n"),
                    r->lnr, (int)errlen, s+erroff);
       else
-        log_error (_("line %d: invalid subject name `%s' at pos %d\n"),
+        log_error (_("line %d: invalid subject name '%s' at pos %d\n"),
                    r->lnr, s, (int)erroff);
 
       xfree (cardkeyid);
@@ -554,10 +557,10 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
         {
           r = get_parameter (para, pISSUERDN, 0);
           if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
-            log_error (_("line %d: invalid issuer name label `%.*s'\n"),
+            log_error (_("line %d: invalid issuer name label '%.*s'\n"),
                        r->lnr, (int)errlen, string+erroff);
           else
-            log_error (_("line %d: invalid issuer name `%s' at pos %d\n"),
+            log_error (_("line %d: invalid issuer name '%s' at pos %d\n"),
                        r->lnr, string, (int)erroff);
           xfree (cardkeyid);
           return gpg_error (GPG_ERR_INV_PARAMETER);
@@ -593,7 +596,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
       if (rc)
         {
           r = get_parameter (para, pKEYTYPE, 0);
-          log_error (_("line %d: error getting signing key by keygrip `%s'"
+          log_error (_("line %d: error getting signing key by keygrip '%s'"
                        ": %s\n"), r->lnr, s, gpg_strerror (rc));
           xfree (cardkeyid);
           return rc;
@@ -618,6 +621,21 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
       }
   }
 
+  /* Check the optional AuthorityKeyId.  */
+  string = get_parameter_value (para, pAUTHKEYID, 0);
+  if (string)
+    {
+      for (s=string, i=0; hexdigitp (s); s++, i++)
+        ;
+      if (*s || (i&1))
+        {
+          r = get_parameter (para, pAUTHKEYID, 0);
+          log_error (_("line %d: invalid authority-key-id\n"), r->lnr);
+          xfree (cardkeyid);
+          return gpg_error (GPG_ERR_INV_PARAMETER);
+        }
+    }
+
   /* Check the optional SubjectKeyId.  */
   string = get_parameter_value (para, pSUBJKEYID, 0);
   if (string)
@@ -678,7 +696,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
       if (rc)
         {
           r = get_parameter (para, pKEYTYPE, 0);
-          log_error (_("line %d: error reading key `%s' from card: %s\n"),
+          log_error (_("line %d: error reading key '%s' from card: %s\n"),
                      r->lnr, cardkeyid, gpg_strerror (rc));
           xfree (sigkey);
           xfree (cardkeyid);
@@ -691,7 +709,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
       if (rc)
         {
           r = get_parameter (para, pKEYTYPE, 0);
-          log_error (_("line %d: error getting key by keygrip `%s': %s\n"),
+          log_error (_("line %d: error getting key by keygrip '%s': %s\n"),
                      r->lnr, s, gpg_strerror (rc));
           xfree (sigkey);
           xfree (cardkeyid);
@@ -701,7 +719,7 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
   else if (!outctrl->dryrun) /* Generate new key.  */
     {
       sprintf (numbuf, "%u", nbits);
-      snprintf ((char*)keyparms, DIM (keyparms)-1,
+      snprintf ((char*)keyparms, DIM (keyparms),
                 "(6:genkey(3:rsa(5:nbits%d:%s)))",
                 (int)strlen (numbuf), numbuf);
       rc = gpgsm_agent_genkey (ctrl, keyparms, &public);
@@ -789,7 +807,7 @@ create_request (ctrl_t ctrl,
   if (string)
     mdalgo = gcry_md_map_name (string);
   else
-    mdalgo = GCRY_MD_SHA1;
+    mdalgo = GCRY_MD_SHA256;
   rc = gcry_md_open (&md, mdalgo, 0);
   if (rc)
     {
@@ -899,38 +917,53 @@ create_request (ctrl_t ctrl,
 
   /* Set key usage flags.  */
   use = get_parameter_uint (para, pKEYUSAGE);
-  if (use == GCRY_PK_USAGE_SIGN)
-    {
-      /* For signing only we encode the bits:
-         KSBA_KEYUSAGE_DIGITAL_SIGNATURE
-         KSBA_KEYUSAGE_NON_REPUDIATION */
-      err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
-                                        "\x03\x02\x06\xC0", 4);
-    }
-  else if (use == GCRY_PK_USAGE_ENCR)
-    {
-      /* For encrypt only we encode the bits:
-         KSBA_KEYUSAGE_KEY_ENCIPHERMENT
-         KSBA_KEYUSAGE_DATA_ENCIPHERMENT */
-      err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
-                                        "\x03\x02\x04\x30", 4);
-    }
-  else if (use == GCRY_PK_USAGE_CERT)
+  if (use)
     {
-      /* For certify only we encode the bits:
-         KSBA_KEYUSAGE_KEY_CERT_SIGN
-         KSBA_KEYUSAGE_CRL_SIGN */
-      err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
-                                        "\x03\x02\x01\x06", 4);
-    }
-  else
-    err = 0; /* Both or none given: don't request one. */
-  if (err)
-    {
-      log_error ("error setting the key usage: %s\n",
-                 gpg_strerror (err));
-      rc = err;
-      goto leave;
+      unsigned int mask, pos;
+      unsigned char der[4];
+
+      der[0] = 0x03;
+      der[1] = 0x02;
+      der[2] = 0;
+      der[3] = 0;
+      if ((use & GCRY_PK_USAGE_SIGN))
+        {
+          /* For signing only we encode the bits:
+             KSBA_KEYUSAGE_DIGITAL_SIGNATURE
+             KSBA_KEYUSAGE_NON_REPUDIATION  = 0b11 -> 0b11000000 */
+          der[3] |= 0xc0;
+        }
+      if ((use & GCRY_PK_USAGE_ENCR))
+        {
+          /* For encrypt only we encode the bits:
+             KSBA_KEYUSAGE_KEY_ENCIPHERMENT
+             KSBA_KEYUSAGE_DATA_ENCIPHERMENT = 0b1100 -> 0b00110000 */
+          der[3] |= 0x30;
+        }
+      if ((use & GCRY_PK_USAGE_CERT))
+        {
+          /* For certify only we encode the bits:
+             KSBA_KEYUSAGE_KEY_CERT_SIGN
+             KSBA_KEYUSAGE_CRL_SIGN      = 0b1100000 -> 0b00000110 */
+          der[3] |= 0x06;
+        }
+
+      /* Count number of unused bits.  */
+      for (mask=1, pos=0; pos < 8 * sizeof mask; pos++, mask <<= 1)
+        {
+          if ((der[3] & mask))
+            break;
+          der[2]++;
+        }
+
+      err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1, der, 4);
+      if (err)
+        {
+          log_error ("error setting the key usage: %s\n",
+                     gpg_strerror (err));
+          rc = err;
+          goto leave;
+        }
     }
 
 
@@ -1095,6 +1128,44 @@ create_request (ctrl_t ctrl,
           }
       }
 
+      /* Insert the AuthorityKeyId.  */
+      string = get_parameter_value (para, pAUTHKEYID, 0);
+      if (string)
+        {
+          char *hexbuf;
+
+          /* Allocate a buffer for in-place conversion.  We also add 4
+             extra bytes space for the tags and lengths fields.  */
+          hexbuf = xtrymalloc (4 + strlen (string) + 1);
+          if (!hexbuf)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          strcpy (hexbuf+4, string);
+          for (p=hexbuf+4, len=0; p[0] && p[1]; p += 2)
+            ((unsigned char*)hexbuf)[4+len++] = xtoi_2 (p);
+          if (len > 125)
+            {
+              err = gpg_error (GPG_ERR_TOO_LARGE);
+              xfree (hexbuf);
+              goto leave;
+            }
+          hexbuf[0] = 0x30;  /* Tag for a Sequence.  */
+          hexbuf[1] = len+2;
+          hexbuf[2] = 0x80;  /* Context tag for an implicit Octet string.  */
+          hexbuf[3] = len;
+          err = ksba_certreq_add_extension (cr, oidstr_authorityKeyIdentifier,
+                                            0,
+                                            hexbuf, 4+len);
+          xfree (hexbuf);
+          if (err)
+            {
+              log_error ("error setting the authority-key-id: %s\n",
+                         gpg_strerror (err));
+              goto leave;
+            }
+        }
 
       /* Insert the SubjectKeyId.  */
       string = get_parameter_value (para, pSUBJKEYID, 0);