Update SoftHSM v2.0 to the latest version
[aaf/sshsm.git] / SoftHSMv2 / src / bin / keyconv / softhsm2-keyconv.cpp
diff --git a/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.cpp b/SoftHSMv2/src/bin/keyconv/softhsm2-keyconv.cpp
new file mode 100644 (file)
index 0000000..aeb75c3
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2010 .SE (The Internet Infrastructure Foundation)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/************************************************************
+*
+* softhsm2-keyconv
+*
+* This program is for converting from BIND .private-key
+* format to PKCS#8 key file format. So that keys can be
+* imported from BIND to SoftHSM.
+*
+* Some of the design/code is from keyconv.c written by
+* Hakan Olsson and Jakob Schlyter in 2000 and 2001.
+*
+************************************************************/
+
+#include <config.h>
+#include "softhsm2-keyconv.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#else
+#include <io.h>
+#define S_IRUSR 0400
+#define S_IWUSR 0200
+#define open _open
+#define close _close
+#endif
+#include <iostream>
+#include <fstream>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void usage()
+{
+       printf("Converting from BIND .private-key format to PKCS#8 key file format.\n");
+       printf("Usage: softhsm2-keyconv [OPTIONS]\n");
+       printf("Options:\n");
+       printf("  -h                  Shows this help screen.\n");
+       printf("  --help              Shows this help screen.\n");
+       printf("  --in <path>         The path to the input file.\n");
+       printf("  --out <path>        The path to the output file.\n");
+       printf("  --pin <PIN>         To encrypt PKCS#8 file. Optional.\n");
+       printf("  -v                  Show version info.\n");
+       printf("  --version           Show version info.\n");
+}
+
+// Give a number to each option
+enum {
+       OPT_HELP = 0x100,
+       OPT_IN,
+       OPT_OUT,
+       OPT_PIN,
+       OPT_VERSION
+};
+
+// Define the options
+static const struct option long_options[] = {
+       { "help",    0, NULL, OPT_HELP },
+       { "in",      1, NULL, OPT_IN },
+       { "out",     1, NULL, OPT_OUT },
+       { "pin",     1, NULL, OPT_PIN },
+       { "version", 0, NULL, OPT_VERSION },
+       { NULL,      0, NULL, 0 }
+};
+
+int main(int argc, char* argv[])
+{
+       int option_index = 0;
+       int opt, result;
+
+       char* in_path = NULL;
+       char* out_path = NULL;
+       char* file_pin = NULL;
+
+       if (argc == 1)
+       {
+               usage();
+               exit(0);
+       }
+
+       while ((opt = getopt_long(argc, argv, "hv", long_options, &option_index)) != -1)
+       {
+               switch (opt)
+               {
+                       case OPT_IN:
+                               in_path = optarg;
+                               break;
+                       case OPT_OUT:
+                               out_path = optarg;
+                               break;
+                       case OPT_PIN:
+                               file_pin = optarg;
+                               break;
+                       case OPT_VERSION:
+                       case 'v':
+                               printf("%s\n", PACKAGE_VERSION);
+                               exit(0);
+                               break;
+                       case OPT_HELP:
+                       case 'h':
+                       default:
+                               usage();
+                               exit(0);
+                               break;
+               }
+       }
+
+       // We should convert to PKCS#8
+       result = to_pkcs8(in_path, out_path, file_pin);
+
+       return result;
+}
+
+// Convert from BIND to PKCS#8
+int to_pkcs8(char* in_path, char* out_path, char* file_pin)
+{
+       FILE* file_pointer = NULL;
+       char line[MAX_LINE], data[MAX_LINE];
+       char* value_pointer = NULL;
+       int lineno = 0, m, n, error = 0, found, algorithm = DNS_KEYALG_ERROR, data_length;
+       uint32_t bitfield = 0;
+       key_material_t pkey[TAG_MAX];
+
+       if (in_path == NULL)
+       {
+               fprintf(stderr, "ERROR: A path to the input file must be supplied. Use --in <path>\n");
+               return 1;
+       }
+
+       if (out_path == NULL)
+       {
+               fprintf(stderr, "ERROR: A path to the output file must be supplied. Use --out <path>\n");
+               return 1;
+       }
+
+       file_pointer = fopen(in_path, "r");
+       if (file_pointer == NULL)
+       {
+               fprintf(stderr, "ERROR: Could not open input file %.100s for reading.\n", in_path);
+               return 1;
+       }
+
+       // Loop over all of the lines
+       while (fgets(line, MAX_LINE, file_pointer) != NULL)
+       {
+               lineno++;
+
+               // Find the current text field in the BIND file.
+               for (m = 0, found = -1; found == -1 && file_tags[m]; m++)
+               {
+                       if (strncasecmp(line, file_tags[m], strlen(file_tags[m])) == 0)
+                       {
+                               found = m;
+                       }
+               }
+
+               // The text files is not recognized.
+               if (found == -1)
+               {
+                       fprintf(stderr, "ERROR: Unrecognized input line %i\n", lineno);
+                       fprintf(stderr, "ERROR: --> %s", line);
+                       continue;
+               }
+
+               // Point to the data for this text field.
+               value_pointer = line + strlen(file_tags[found]) + 1;
+
+               // Continue if we are at the end of the string
+               if (*value_pointer == 0)
+               {
+                       continue;
+               }
+
+               // Check that we do not get duplicates.
+               if (bitfield & (1 << found))
+               {
+                       fprintf(stderr, "ERROR: Duplicate \"%s\" field, line %i - ignored\n",
+                                       file_tags[found], lineno);
+                       continue;
+               }
+               bitfield |= (1 << found);
+
+               // Handle the data for this text field.
+               switch (found)
+               {
+                       case TAG_VERSION:
+                               if (sscanf(value_pointer, "v%i.%i", &m, &n) != 2)
+                               {
+                                       fprintf(stderr, "ERROR: Invalid/unknown version string "
+                                                       "(%.100s).\n", value_pointer);
+                                       error = 1;
+                                       break;
+                               }
+                               if (m > FILE_MAJOR_VERSION || (m == FILE_MAJOR_VERSION && n > FILE_MINOR_VERSION))
+                               {
+                                       fprintf(stderr, "ERROR: Cannot parse this version of file format, "
+                                                       "v%i.%i.\n", m, n);
+                                       error = 1;
+                               }
+                               break;
+                       case TAG_ALGORITHM:
+                               algorithm = strtol(value_pointer, NULL, 10);
+                               break;
+                       // RSA
+                       case TAG_MODULUS:
+                       case TAG_PUBEXP:
+                       case TAG_PRIVEXP:
+                       case TAG_PRIME1:
+                       case TAG_PRIME2:
+                       case TAG_EXP1:
+                       case TAG_EXP2:
+                       case TAG_COEFF:
+                       // DSA
+                       case TAG_PRIME:
+                       case TAG_SUBPRIME:
+                       case TAG_BASE:
+                       case TAG_PRIVVAL:
+                       case TAG_PUBVAL:
+                               data_length = b64_pton(value_pointer, (unsigned char*)data, MAX_LINE);
+                               if (data_length == -1)
+                               {
+                                       error = 1;
+                                       fprintf(stderr, "ERROR: Could not parse the base64 string on line %i.\n", lineno);
+                               }
+                               else
+                               {
+                                       pkey[found].big = malloc(data_length);
+                                       if (!pkey[found].big)
+                                       {
+                                               fprintf(stderr, "ERROR: Could not allocate memory.\n");
+                                               error = 1;
+                                               break;
+                                       }
+                                       memcpy(pkey[found].big, data, data_length);
+                                       pkey[found].size = data_length;
+                               }
+                               break;
+                       // Do not need these
+                       case TAG_CREATED:
+                       case TAG_PUBLISH:
+                       case TAG_ACTIVATE:
+                       default:
+                               break;
+               }
+       }
+
+       fclose(file_pointer);
+
+       // Something went wrong. Clean up and quit.
+       if (error)
+       {
+               free_key_material(pkey);
+               return error;
+       }
+
+       // Create and set file permissions if the file does not exist.
+       int fd = open(out_path, O_CREAT, S_IRUSR | S_IWUSR);
+       if (fd == -1)
+       {
+               fprintf(stderr, "ERROR: Could not open the output file: %s (errno %i)\n",
+                       out_path, errno);
+               free_key_material(pkey);
+               return 1;
+       }
+       ::close(fd);
+
+       crypto_init();
+
+       // Save the the key to the disk
+       switch (algorithm)
+       {
+               case DNS_KEYALG_ERROR:
+                       fprintf(stderr, "ERROR: The algorithm %i was not given in the file.\n",
+                                       algorithm);
+                       error = 1;
+                       break;
+               case DNS_KEYALG_RSAMD5:
+               case DNS_KEYALG_RSASHA1:
+               case DNS_KEYALG_RSASHA1_NSEC3_SHA1:
+               case DNS_KEYALG_RSASHA256:
+               case DNS_KEYALG_RSASHA512:
+                       error = save_rsa_pkcs8(out_path, file_pin, pkey);
+                       break;
+               case DNS_KEYALG_DSA:
+               case DNS_KEYALG_DSA_NSEC3_SHA1:
+                       error = save_dsa_pkcs8(out_path, file_pin, pkey);
+                       break;
+               case DNS_KEYALG_ECC:
+               case DNS_KEYALG_ECC_GOST:
+               default:
+                       fprintf(stderr, "ERROR: The algorithm %i is not supported.\n",
+                                       algorithm);
+                       error = 1;
+                       break;
+       }
+
+       crypto_final();
+       free_key_material(pkey);
+
+       return error;
+}
+
+// Free allocated memory
+void free_key_material(key_material_t* pkey)
+{
+       int i;
+
+       if (!pkey)
+       {
+               return;
+       }
+
+       for (i = 0; i < TAG_MAX; i++)
+       {
+               if (pkey[i].big)
+               {
+                       free(pkey[i].big);
+               }
+       }
+}