+/* FIXME: keyid should be const also */
+int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_openpgp_keyid_t* keyid) {
+ gnutls_openpgp_keyid_t curkeyid;
+ int ret;
+ int subkeyidx;
+ int subkeycount;
+ int found = 0;
+ gnutls_datum_t m, e, p, q, g, y, algolabel;
+ unsigned int bits;
+ gnutls_pk_algorithm_t algo;
+ const gnutls_datum_t* all[5];
+ const char* algoname;
+ int mpicount;
+ /* output_data must be at least 2 chars longer than the maximum possible
+ algorithm name: */
+ char output_data[20];
+
+ /* variables for the output conversion: */
+ int pipestatus;
+ int pipefd, child_pid;
+ char* const b64args[] = {"/usr/bin/base64", "--wrap=0", NULL};
+
+ init_datum(&m);
+ init_datum(&e);
+ init_datum(&p);
+ init_datum(&q);
+ init_datum(&g);
+ init_datum(&algolabel);
+
+
+ /* figure out if we've got the right thing: */
+ subkeycount = gnutls_openpgp_crt_get_subkey_count(*pgp_crt);
+ if (subkeycount < 0) {
+ err("Could not determine subkey count (got value %d)\n", subkeycount);
+ return 1;
+ }
+
+ if ((keyid == NULL) &&
+ (subkeycount > 0)) {
+ err("No keyid passed in, but there were %d keys to choose from\n", subkeycount + 1);
+ return 1;
+ }
+
+ if (keyid != NULL) {
+ ret = gnutls_openpgp_crt_get_key_id(*pgp_crt, curkeyid);
+ if (ret) {
+ err("Could not get keyid (error: %d)\n", ret);
+ return 1;
+ }
+ }
+ if ((keyid == NULL) || (memcmp(*keyid, curkeyid, sizeof(gnutls_openpgp_keyid_t)) == 0)) {
+ /* we want to export the primary key: */
+ err("exporting primary key\n");
+
+ /* FIXME: this is almost identical to the block below for subkeys.
+ This clumsiness seems inherent in the gnutls OpenPGP API,
+ though. ugh. */
+ algo = gnutls_openpgp_crt_get_pk_algorithm(*pgp_crt, &bits);
+ if (algo < 0) {
+ err("failed to get the algorithm of the OpenPGP public key (error: %d)\n", algo);
+ return algo;
+ } else if (algo == GNUTLS_PK_RSA) {
+ err("OpenPGP RSA certificate, with %d bits\n", bits);
+ ret = gnutls_openpgp_crt_get_pk_rsa_raw(*pgp_crt, &m, &e);
+ if (GNUTLS_E_SUCCESS != ret) {
+ err ("failed to export RSA key parameters (error: %d)\n", ret);
+ return 1;
+ }
+ } else if (algo == GNUTLS_PK_DSA) {
+ err("OpenPGP DSA Key, with %d bits\n", bits);
+ ret = gnutls_openpgp_crt_get_pk_dsa_raw(*pgp_crt, &p, &q, &g, &y);
+ if (GNUTLS_E_SUCCESS != ret) {
+ err ("failed to export DSA key parameters (error: %d)\n", ret);
+ return 1;
+ }
+ }
+ found = 1;
+
+ } else {
+ /* lets trawl through the subkeys until we find the one we want: */
+ for (subkeyidx = 0; (subkeyidx < subkeycount) && !found; subkeyidx++) {
+ ret = gnutls_openpgp_crt_get_subkey_id(*pgp_crt, subkeyidx, curkeyid);
+ if (ret) {
+ err("Could not get keyid of subkey with index %d (error: %d)\n", subkeyidx, ret);
+ return 1;
+ }
+ if (memcmp(*keyid, curkeyid, sizeof(gnutls_openpgp_keyid_t)) == 0) {
+ err("exporting subkey index %d\n", subkeyidx);
+
+ /* FIXME: this is almost identical to the block above for the
+ primary key. */
+ algo = gnutls_openpgp_crt_get_subkey_pk_algorithm(*pgp_crt, subkeyidx, &bits);
+ if (algo < 0) {
+ err("failed to get the algorithm of the OpenPGP public key (error: %d)\n", algo);
+ return algo;
+ } else if (algo == GNUTLS_PK_RSA) {
+ err("OpenPGP RSA certificate, with %d bits\n", bits);
+ ret = gnutls_openpgp_crt_get_subkey_pk_rsa_raw(*pgp_crt, subkeyidx, &m, &e);
+ if (GNUTLS_E_SUCCESS != ret) {
+ err ("failed to export RSA key parameters (error: %d)\n", ret);
+ return 1;
+ }
+ } else if (algo == GNUTLS_PK_DSA) {
+ err("OpenPGP DSA Key, with %d bits\n", bits);
+ ret = gnutls_openpgp_crt_get_subkey_pk_dsa_raw(*pgp_crt, subkeyidx, &p, &q, &g, &y);
+ if (GNUTLS_E_SUCCESS != ret) {
+ err ("failed to export DSA key parameters (error: %d)\n", ret);
+ return 1;
+ }
+ }
+ found = 1;
+
+ }
+ }
+ }
+
+ if (!found) {
+ err("Could not find key in input\n");
+ return 1;
+ }
+
+ /* if we made it this far, we've got MPIs, and we've got the
+ algorithm, so we just need to emit the info */
+ if (algo == GNUTLS_PK_RSA) {
+ algoname = "ssh-rsa";
+ mpicount = 3;
+
+ all[0] = &algolabel;
+ all[1] = &e;
+ all[2] = &m;
+ } else if (algo == GNUTLS_PK_DSA) {
+ algoname = "ssh-dss";
+ mpicount = 5;
+
+ all[0] = &algolabel;
+ all[1] = &p;
+ all[2] = &q;
+ all[3] = &g;
+ all[4] = &y;
+ } else {
+ err("Key algorithm was neither DSA nor RSA (it was %d). Can't deal. Sorry!\n", algo);
+ return 1;
+ }
+
+ if (ret = datum_from_string(&algolabel, algoname), ret) {
+ err("couldn't label string (error: %d)\n", ret);
+ return ret;
+ }
+
+ snprintf(output_data, sizeof(output_data), "%s ", algoname);
+
+ pipefd = create_writing_pipe(&child_pid, b64args[0], b64args);
+ if (pipefd < 0) {
+ err("failed to create a writing pipe (returned %d)\n", pipefd);
+ return pipefd;
+ }
+
+ write(1, output_data, strlen(output_data));
+
+ if (0 != write_data_fd_with_length(pipefd, all, mpicount)) {
+ err("was not able to write out RSA key data\n");
+ return 1;
+ }
+ close(pipefd);
+ if (child_pid != waitpid(child_pid, &pipestatus, 0)) {
+ err("could not wait for child process to return for some reason.\n");
+ return 1;
+ }
+ if (pipestatus != 0) {
+ err("base64 pipe died with return code %d\n", pipestatus);
+ return pipestatus;
+ }
+
+ write(1, "\n", 1);
+
+
+ return 0;
+}
+
+
+