X-Git-Url: https://git.exim.org/users/jgh/exim.git/blobdiff_plain/a799883d8ad340d935db4d729a31c02cb8a1d977..43042f3dab3201f2339f2be0a70e0d67ae7e5386:/src/util/gen_pkcs3.c diff --git a/src/util/gen_pkcs3.c b/src/util/gen_pkcs3.c index ae7e7610a..6a467e07a 100644 --- a/src/util/gen_pkcs3.c +++ b/src/util/gen_pkcs3.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Phil Pennock. +/* Copyright (C) 2012,2016 Phil Pennock. * This is distributed as part of Exim and licensed under the GPL. * See the file "NOTICE" for more details. */ @@ -7,6 +7,16 @@ * c99 $(pkg-config --cflags openssl) gen_pkcs3.c $(pkg-config --libs openssl) */ +/* + * Rationale: + * The Diffie-Hellman primes which are embedded into Exim as named primes for + * the tls_dhparam option are in the std-crypto.c file. The source for those + * comes from various RFCs, where they are given in hexadecimal form. + * + * This tool provides convenient conversion, to reduce the risk of human + * error in transcription. + */ + #include #include #include @@ -76,7 +86,7 @@ bn_from_text(const char *text) rc = BN_hex2bn(&b, spaceless); if (rc != p - spaceless) - die("BN_hex2bn did not convert entire input; took %d of %z bytes", + die("BN_hex2bn did not convert entire input; took %d of %zu bytes", rc, p - spaceless); return b; @@ -124,7 +134,7 @@ emit_c_format_dh(FILE *stream, DH *dh) break; } *nl = '\0'; - fprintf(stream, "\"%s\\n\"\n", p); + fprintf(stream, "\"%s\\n\"%s\n", p, (nl == end - 1 ? ";" : "")); p = nl + 1; } } @@ -133,9 +143,11 @@ emit_c_format_dh(FILE *stream, DH *dh) void __attribute__((__noreturn__)) usage(FILE *stream, int exitcode) { - fprintf(stream, "Usage: %s [-CPcst] \n" + fprintf(stream, "Usage: %s [-CPcst] []\n" "Both dh_p and dh_g should be hex strings representing the numbers\n" +"The same applies to the optional dh_q (prime-order subgroup).\n" "They may contain whitespace.\n" +"Older values, dh_g is often just '2', not a long string.\n" "\n" " -C show C string form of PEM result\n" " -P do not show PEM\n" @@ -151,7 +163,7 @@ usage(FILE *stream, int exitcode) int main(int argc, char *argv[]) { - BIGNUM *p, *g; + BIGNUM *p, *g, *q; DH *dh; int ch; bool perform_dh_check = false; @@ -159,6 +171,7 @@ main(int argc, char *argv[]) bool show_numbers = false; bool show_pem = true; bool show_text = false; + bool given_q = false; while ((ch = getopt(argc, argv, "CPcsth")) != -1) { switch (ch) { @@ -191,25 +204,49 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - if (argc != 3) { + if ((argc < 3) || (argc > 4)) { fprintf(stderr, "argc: %d\n", argc); usage(stderr, 1); } + // If we use DH_set0_pqg instead of setting dh fields directly; the q value + // is optional and may be NULL. + // Just blank them all. + p = g = q = NULL; + p = bn_from_text(argv[1]); g = bn_from_text(argv[2]); + if (argc >= 4) { + q = bn_from_text(argv[3]); + given_q = true; + } if (show_numbers) { printf("p = "); BN_print_fp(stdout, p); printf("\ng = "); BN_print_fp(stdout, g); + if (given_q) { + printf("\nq = "); + BN_print_fp(stdout, q); + } printf("\n"); } dh = DH_new(); + // The documented method for setting q appeared in OpenSSL 1.1.0. +#if OPENSSL_VERSION_NUMBER >= 0x1010000f + // NULL okay for q; yes, the optional value is in the middle. + if (DH_set0_pqg(dh, p, q, g) != 1) { + die_openssl_err("initialising DH pqg values failed"); + } +#else dh->p = p; dh->g = g; + if (given_q) { + dh->q = q; + } +#endif if (perform_dh_check) our_dh_check(dh); @@ -224,6 +261,6 @@ main(int argc, char *argv[]) PEM_write_DHparams(stdout, dh); } - DH_free(dh); /* should free p & g too */ + DH_free(dh); /* should free p,g (& q if non-NULL) too */ return 0; }