+
+ return 0;
+}
+
+
+static int
+gen_card_key (int algo, int keyno, int is_primary,
+ KBNODE pub_root, KBNODE sec_root,
+ u32 expireval, struct para_data_s *para)
+{
+#ifdef ENABLE_CARD_SUPPORT
+ int rc;
+ const char *s;
+ struct agent_card_genkey_s info;
+ PACKET *pkt;
+ PKT_secret_key *sk;
+ PKT_public_key *pk;
+
+ assert (algo == PUBKEY_ALGO_RSA);
+
+ /* Fixme: We don't have the serialnumber available, thus passing NULL. */
+ rc = agent_scd_genkey (&info, keyno, 1, NULL);
+/* if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
+/* { */
+/* tty_printf ("\n"); */
+/* log_error ("WARNING: key does already exists!\n"); */
+/* tty_printf ("\n"); */
+/* if ( cpr_get_answer_is_yes( "keygen.card.replace_key", */
+/* _("Replace existing key? "))) */
+/* rc = agent_scd_genkey (&info, keyno, 1); */
+/* } */
+
+ if (rc)
+ {
+ log_error ("key generation failed: %s\n", gpg_strerror (rc));
+ return rc;
+ }
+ if ( !info.n || !info.e )
+ {
+ log_error ("communication error with SCD\n");
+ mpi_free (info.n);
+ mpi_free (info.e);
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+
+
+ pk = xcalloc (1, sizeof *pk );
+ sk = xcalloc (1, sizeof *sk );
+ sk->timestamp = pk->timestamp = info.created_at;
+ sk->version = pk->version = 4;
+ if (expireval)
+ sk->expiredate = pk->expiredate = pk->timestamp + expireval;
+ sk->pubkey_algo = pk->pubkey_algo = algo;
+ pk->pkey[0] = info.n;
+ pk->pkey[1] = info.e;
+ sk->skey[0] = mpi_copy (pk->pkey[0]);
+ sk->skey[1] = mpi_copy (pk->pkey[1]);
+ sk->skey[2] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10);
+ sk->is_protected = 1;
+ sk->protect.s2k.mode = 1002;
+ s = get_parameter_value (para, pSERIALNO);
+ if (s)
+ {
+ for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
+ sk->protect.ivlen++, s += 2)
+ sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
+ }
+
+ pkt = xcalloc (1,sizeof *pkt);
+ pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+ pkt->pkt.public_key = pk;
+ add_kbnode(pub_root, new_kbnode( pkt ));
+
+ pkt = xcalloc (1,sizeof *pkt);
+ pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
+ pkt->pkt.secret_key = sk;
+ add_kbnode(sec_root, new_kbnode( pkt ));
+
+ return 0;
+#else
+ return -1;
+#endif /*!ENABLE_CARD_SUPPORT*/
+}
+
+
+
+static int
+gen_card_key_with_backup (int algo, int keyno, int is_primary,
+ KBNODE pub_root, KBNODE sec_root,
+ u32 expireval, struct para_data_s *para,
+ const char *backup_dir)
+{
+#ifdef ENABLE_CARD_SUPPORT
+ int rc;
+ const char *s;
+ PACKET *pkt;
+ PKT_secret_key *sk, *sk_unprotected, *sk_protected;
+ PKT_public_key *pk;
+ size_t n;
+ int i;
+
+ rc = generate_raw_key (algo, 1024, make_timestamp (),
+ &sk_unprotected, &sk_protected);
+ if (rc)
+ return rc;
+
+ /* First, store the key to the card. */
+ rc = save_unprotected_key_to_card (sk_unprotected, keyno);
+ if (rc)
+ {
+ log_error (_("storing key onto card failed: %s\n"), g10_errstr (rc));
+ free_secret_key (sk_unprotected);
+ free_secret_key (sk_protected);
+ return rc;
+ }
+
+ /* Get rid of the secret key parameters and store the serial numer. */
+ sk = sk_unprotected;
+ n = pubkey_get_nskey (sk->pubkey_algo);
+ for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++)
+ {
+ mpi_free (sk->skey[i]);
+ sk->skey[i] = NULL;
+ }
+ i = pubkey_get_npkey (sk->pubkey_algo);
+ sk->skey[i] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10);
+ sk->is_protected = 1;
+ sk->protect.s2k.mode = 1002;
+ s = get_parameter_value (para, pSERIALNO);
+ assert (s);
+ for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
+ sk->protect.ivlen++, s += 2)
+ sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
+
+ /* Now write the *protected* secret key to the file. */
+ {
+ char name_buffer[50];
+ char *fname;
+ IOBUF fp;
+ mode_t oldmask;
+
+ keyid_from_sk (sk, NULL);
+ sprintf (name_buffer,"sk_%08lX%08lX.gpg",
+ (ulong)sk->keyid[0], (ulong)sk->keyid[1]);
+
+ fname = make_filename (backup_dir, name_buffer, NULL);
+ oldmask = umask (077);
+ if (is_secured_filename (fname))
+ {
+ fp = NULL;
+ errno = EPERM;
+ }
+ else
+ fp = iobuf_create (fname);
+ umask (oldmask);
+ if (!fp)
+ {
+ log_error (_("can't create backup file `%s': %s\n"),
+ fname, strerror(errno) );
+ xfree (fname);
+ free_secret_key (sk_unprotected);
+ free_secret_key (sk_protected);
+ return G10ERR_OPEN_FILE;
+ }
+
+ pkt = xcalloc (1, sizeof *pkt);
+ pkt->pkttype = PKT_SECRET_KEY;
+ pkt->pkt.secret_key = sk_protected;
+ sk_protected = NULL;
+
+ rc = build_packet (fp, pkt);
+ if (rc)
+ {
+ log_error("build packet failed: %s\n", g10_errstr(rc) );
+ iobuf_cancel (fp);
+ }
+ else
+ {
+ byte array[MAX_FINGERPRINT_LEN];
+ char *fprbuf, *p;
+
+ iobuf_close (fp);
+ iobuf_ioctl (NULL, 2, 0, (char*)fname);
+ log_info (_("NOTE: backup of card key saved to `%s'\n"), fname);
+
+ fingerprint_from_sk (sk, array, &n);
+ p = fprbuf = xmalloc (MAX_FINGERPRINT_LEN*2 + 1 + 1);
+ for (i=0; i < n ; i++, p += 2)
+ sprintf (p, "%02X", array[i]);
+ *p++ = ' ';
+ *p = 0;
+
+ write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED,
+ fprbuf,
+ fname, strlen (fname),
+ 0);
+ xfree (fprbuf);
+ }
+ free_packet (pkt);
+ xfree (pkt);
+ xfree (fname);
+ if (rc)
+ {
+ free_secret_key (sk_unprotected);
+ return rc;
+ }
+ }
+
+ /* Create the public key from the secret key. */
+ pk = xcalloc (1, sizeof *pk );
+ pk->timestamp = sk->timestamp;
+ pk->version = sk->version;
+ if (expireval)
+ pk->expiredate = sk->expiredate = sk->timestamp + expireval;
+ pk->pubkey_algo = sk->pubkey_algo;
+ n = pubkey_get_npkey (sk->pubkey_algo);
+ for (i=0; i < n; i++)
+ pk->pkey[i] = mpi_copy (sk->skey[i]);
+
+ /* Build packets and add them to the node lists. */
+ pkt = xcalloc (1,sizeof *pkt);
+ pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+ pkt->pkt.public_key = pk;
+ add_kbnode(pub_root, new_kbnode( pkt ));
+
+ pkt = xcalloc (1,sizeof *pkt);
+ pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
+ pkt->pkt.secret_key = sk;
+ add_kbnode(sec_root, new_kbnode( pkt ));
+
+ return 0;
+#else
+ return -1;
+#endif /*!ENABLE_CARD_SUPPORT*/
+}
+
+
+#ifdef ENABLE_CARD_SUPPORT
+int
+save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
+{
+ int rc;
+ unsigned char *rsa_n = NULL;
+ unsigned char *rsa_e = NULL;
+ unsigned char *rsa_p = NULL;
+ unsigned char *rsa_q = NULL;
+ unsigned int rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len;
+ unsigned char *sexp = NULL;
+ unsigned char *p;
+ char numbuf[55], numbuf2[50];
+
+ assert (is_RSA (sk->pubkey_algo));
+ assert (!sk->is_protected);
+
+ /* Copy the parameters into straight buffers. */
+ rsa_n = mpi_get_secure_buffer (sk->skey[0], &rsa_n_len, NULL);
+ rsa_e = mpi_get_secure_buffer (sk->skey[1], &rsa_e_len, NULL);
+ rsa_p = mpi_get_secure_buffer (sk->skey[3], &rsa_p_len, NULL);
+ rsa_q = mpi_get_secure_buffer (sk->skey[4], &rsa_q_len, NULL);
+ if (!rsa_n || !rsa_e || !rsa_p || !rsa_q)
+ {
+ rc = G10ERR_INV_ARG;
+ goto leave;
+ }
+
+ /* Put the key into an S-expression. */
+ sexp = p = xmalloc_secure (30
+ + rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len
+ + 4*sizeof (numbuf) + 25 + sizeof(numbuf) + 20);
+
+ p = stpcpy (p,"(11:private-key(3:rsa(1:n");
+ sprintf (numbuf, "%u:", rsa_n_len);
+ p = stpcpy (p, numbuf);
+ memcpy (p, rsa_n, rsa_n_len);
+ p += rsa_n_len;
+
+ sprintf (numbuf, ")(1:e%u:", rsa_e_len);
+ p = stpcpy (p, numbuf);
+ memcpy (p, rsa_e, rsa_e_len);
+ p += rsa_e_len;
+
+ sprintf (numbuf, ")(1:p%u:", rsa_p_len);
+ p = stpcpy (p, numbuf);
+ memcpy (p, rsa_p, rsa_p_len);
+ p += rsa_p_len;
+
+ sprintf (numbuf, ")(1:q%u:", rsa_q_len);
+ p = stpcpy (p, numbuf);
+ memcpy (p, rsa_q, rsa_q_len);
+ p += rsa_q_len;
+
+ p = stpcpy (p,"))(10:created-at");
+ sprintf (numbuf2, "%lu", (unsigned long)sk->timestamp);
+ sprintf (numbuf, "%lu:", (unsigned long)strlen (numbuf2));
+ p = stpcpy (stpcpy (stpcpy (p, numbuf), numbuf2), "))");
+
+ /* Fixme: Unfortunately we don't have the serialnumber available -
+ thus we can't pass it down to the agent. */
+ rc = agent_scd_writekey (keyno, NULL, sexp, p - sexp);
+
+ leave:
+ xfree (sexp);
+ xfree (rsa_n);
+ xfree (rsa_e);
+ xfree (rsa_p);
+ xfree (rsa_q);
+ return rc;