summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorPhil Pennock <pdp@exim.org>2012-05-27 09:14:39 -0400
committerPhil Pennock <pdp@exim.org>2012-05-27 09:14:39 -0400
commita799883d8ad340d935db4d729a31c02cb8a1d977 (patch)
tree3ceb2a5d711c3430aba48a47cfed59c73d6ddda9 /src/util
parentcae6e576b589efbe9e22cd65e5f890b21ce84f02 (diff)
For DH, use standard primes from RFCs
Diffstat (limited to 'src/util')
-rw-r--r--src/util/gen_pkcs3.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/src/util/gen_pkcs3.c b/src/util/gen_pkcs3.c
new file mode 100644
index 000000000..ae7e7610a
--- /dev/null
+++ b/src/util/gen_pkcs3.c
@@ -0,0 +1,229 @@
+/* Copyright (C) 2012 Phil Pennock.
+ * This is distributed as part of Exim and licensed under the GPL.
+ * See the file "NOTICE" for more details.
+ */
+
+/* Build with:
+ * c99 $(pkg-config --cflags openssl) gen_pkcs3.c $(pkg-config --libs openssl)
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+
+extern const char *__progname;
+
+
+void __attribute__((__noreturn__)) __attribute__((__format__(printf, 1, 2)))
+die(const char *fmt, ...)
+{
+ va_list ap;
+
+ fflush(NULL);
+ fprintf(stderr, "%s: ", __progname);
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ exit(1);
+}
+
+
+void __attribute__((__noreturn__))
+die_openssl_err(const char *msg)
+{
+ char err_string[250];
+ unsigned long e;
+
+ ERR_error_string_n(ERR_get_error(), err_string, sizeof(err_string));
+ die("%s: %s", msg, err_string);
+}
+
+
+static BIGNUM *
+bn_from_text(const char *text)
+{
+ BIGNUM *b;
+ char *p, *spaceless;
+ const char *q, *end;
+ size_t len;
+ int rc;
+
+ len = strlen(text);
+ spaceless = malloc(len);
+ if (!spaceless)
+ die("malloc(%zu) failed: %s", len, strerror(errno));
+
+ for (p = spaceless, q = text, end = text + len;
+ q < end;
+ ++q) {
+ if (!isspace(*q))
+ *p++ = *q;
+ }
+
+ b = NULL;
+ rc = BN_hex2bn(&b, spaceless);
+
+ if (rc != p - spaceless)
+ die("BN_hex2bn did not convert entire input; took %d of %z bytes",
+ rc, p - spaceless);
+
+ return b;
+}
+
+
+static void
+our_dh_check(DH *dh)
+{
+ int rc, errflags = 0;
+
+ rc = DH_check(dh, &errflags);
+ if (!rc) die_openssl_err("DH_check() could not be performed");;
+
+ /* We ignore DH_UNABLE_TO_CHECK_GENERATOR because some of the invocations
+ * deliberately provide generators other than 2 or 5. */
+
+ if (errflags & DH_CHECK_P_NOT_SAFE_PRIME)
+ die("DH_check(): p not a safe prime");
+ if (errflags & DH_NOT_SUITABLE_GENERATOR)
+ die("DH_check(): g not suitable as generator");
+}
+
+
+static void
+emit_c_format_dh(FILE *stream, DH *dh)
+{
+ BIO *bio;
+ long length;
+ char *data, *end, *p, *nl;
+
+ bio = BIO_new(BIO_s_mem());
+ PEM_write_bio_DHparams(bio, dh);
+ length = BIO_get_mem_data(bio, &data);
+ if (!length)
+ die("no data in memory BIO to format for printing");
+ if (length < 0)
+ die("grr, negative length memory not supported");
+ end = data + length;
+
+ for (p = data; p < end; /**/) {
+ nl = strchr(p, '\n');
+ if (!nl) {
+ fprintf(stream, "\"%s\\n\"\n/* missing final newline */\n", p);
+ break;
+ }
+ *nl = '\0';
+ fprintf(stream, "\"%s\\n\"\n", p);
+ p = nl + 1;
+ }
+}
+
+
+void __attribute__((__noreturn__))
+usage(FILE *stream, int exitcode)
+{
+ fprintf(stream, "Usage: %s [-CPcst] <dh_p> <dh_g>\n"
+"Both dh_p and dh_g should be hex strings representing the numbers\n"
+"They may contain whitespace.\n"
+"\n"
+" -C show C string form of PEM result\n"
+" -P do not show PEM\n"
+" -c run OpenSSL DH_check() on the DH object\n"
+" -s show the parsed p and g\n"
+" -t show text form of certificate\n"
+
+ , __progname);
+ exit(exitcode);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ BIGNUM *p, *g;
+ DH *dh;
+ int ch;
+ bool perform_dh_check = false;
+ bool show_c_form = false;
+ bool show_numbers = false;
+ bool show_pem = true;
+ bool show_text = false;
+
+ while ((ch = getopt(argc, argv, "CPcsth")) != -1) {
+ switch (ch) {
+ case 'C':
+ show_c_form = true;
+ break;
+ case 'P':
+ show_pem = false;
+ break;
+ case 'c':
+ perform_dh_check = true;
+ break;
+ case 's':
+ show_numbers = true;
+ break;
+ case 't':
+ show_text = true;
+ break;
+
+ case 'h':
+ usage(stdout, 0);
+ case '?':
+ die("Unknown option or missing argument -%c", optopt);
+ default:
+ die("Unhandled option -%c", ch);
+ }
+ }
+
+ optind -= 1;
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 3) {
+ fprintf(stderr, "argc: %d\n", argc);
+ usage(stderr, 1);
+ }
+
+ p = bn_from_text(argv[1]);
+ g = bn_from_text(argv[2]);
+
+ if (show_numbers) {
+ printf("p = ");
+ BN_print_fp(stdout, p);
+ printf("\ng = ");
+ BN_print_fp(stdout, g);
+ printf("\n");
+ }
+
+ dh = DH_new();
+ dh->p = p;
+ dh->g = g;
+
+ if (perform_dh_check)
+ our_dh_check(dh);
+
+ if (show_text)
+ DHparams_print_fp(stdout, dh);
+
+ if (show_pem) {
+ if (show_c_form)
+ emit_c_format_dh(stdout, dh);
+ else
+ PEM_write_DHparams(stdout, dh);
+ }
+
+ DH_free(dh); /* should free p & g too */
+ return 0;
+}