=== modified file 'TODO'
--- TODO 2015-07-07 15:49:49 +0000
+++ TODO 2015-07-08 21:18:49 +0000
@@ -20,7 +20,6 @@
* mandos-applet
* mandos-client
-** TODO [#A] --dh-params=FILE
** TODO [#B] Use capabilities instead of seteuid().
https://forums.grsecurity.net/viewtopic.php?f=7&t=2522
** TODO [#B] Use getaddrinfo(hints=AI_NUMERICHOST) instead of inet_pton()
=== modified file 'plugins.d/mandos-client.c'
--- plugins.d/mandos-client.c 2015-07-06 20:29:34 +0000
+++ plugins.d/mandos-client.c 2015-07-08 21:18:49 +0000
@@ -516,6 +516,7 @@
__attribute__((nonnull, warn_unused_result))
static int init_gnutls_global(const char *pubkeyfilename,
const char *seckeyfilename,
+ const char *dhparamsfilename,
mandos_context *mc){
int ret;
unsigned int uret;
@@ -575,24 +576,30 @@
safer_gnutls_strerror(ret));
goto globalfail;
}
- if(mc->dh_bits == 0){
- /* Find out the optimal number of DH bits */
- /* Try to read the private key file */
- gnutls_datum_t buffer = { .data = NULL, .size = 0 };
- {
- int secfile = open(seckeyfilename, O_RDONLY);
- size_t buffer_capacity = 0;
+ /* If a Diffie-Hellman parameters file was given, try to use it */
+ if(dhparamsfilename != NULL){
+ gnutls_datum_t params = { .data = NULL, .size = 0 };
+ do {
+ int dhpfile = open(dhparamsfilename, O_RDONLY);
+ if(dhpfile == -1){
+ perror_plus("open");
+ dhparamsfilename = NULL;
+ break;
+ }
+ size_t params_capacity = 0;
while(true){
- buffer_capacity = incbuffer((char **)&buffer.data,
- (size_t)buffer.size,
- (size_t)buffer_capacity);
- if(buffer_capacity == 0){
+ params_capacity = incbuffer((char **)¶ms.data,
+ (size_t)params.size,
+ (size_t)params_capacity);
+ if(params_capacity == 0){
perror_plus("incbuffer");
- free(buffer.data);
- buffer.data = NULL;
+ free(params.data);
+ params.data = NULL;
+ dhparamsfilename = NULL;
break;
}
- ssize_t bytes_read = read(secfile, buffer.data + buffer.size,
+ ssize_t bytes_read = read(dhpfile,
+ params.data + params.size,
BUFFER_SIZE);
/* EOF */
if(bytes_read == 0){
@@ -601,88 +608,146 @@
/* check bytes_read for failure */
if(bytes_read < 0){
perror_plus("read");
- free(buffer.data);
- buffer.data = NULL;
- break;
- }
- buffer.size += (unsigned int)bytes_read;
- }
- close(secfile);
- }
- /* If successful, use buffer to parse private key */
- gnutls_sec_param_t sec_param = GNUTLS_SEC_PARAM_ULTRA;
- if(buffer.data != NULL){
- {
- gnutls_openpgp_privkey_t privkey = NULL;
- ret = gnutls_openpgp_privkey_init(&privkey);
- if(ret != GNUTLS_E_SUCCESS){
- fprintf_plus(stderr, "Error initializing OpenPGP key"
- " structure: %s", safer_gnutls_strerror(ret));
- free(buffer.data);
- buffer.data = NULL;
- } else {
- ret = gnutls_openpgp_privkey_import(privkey, &buffer,
- GNUTLS_OPENPGP_FMT_BASE64,
- "", 0);
+ free(params.data);
+ params.data = NULL;
+ dhparamsfilename = NULL;
+ break;
+ }
+ params.size += (unsigned int)bytes_read;
+ }
+ if(params.data == NULL){
+ dhparamsfilename = NULL;
+ }
+ if(dhparamsfilename == NULL){
+ break;
+ }
+ ret = gnutls_dh_params_import_pkcs3(mc->dh_params, ¶ms,
+ GNUTLS_X509_FMT_PEM);
+ if(ret != GNUTLS_E_SUCCESS){
+ fprintf_plus(stderr, "Failed to parse DH parameters in file"
+ " \"%s\": %s\n", dhparamsfilename,
+ safer_gnutls_strerror(ret));
+ dhparamsfilename = NULL;
+ }
+ } while(false);
+ }
+ if(dhparamsfilename == NULL){
+ if(mc->dh_bits == 0){
+ /* Find out the optimal number of DH bits */
+ /* Try to read the private key file */
+ gnutls_datum_t buffer = { .data = NULL, .size = 0 };
+ do {
+ int secfile = open(seckeyfilename, O_RDONLY);
+ if(secfile == -1){
+ perror_plus("open");
+ break;
+ }
+ size_t buffer_capacity = 0;
+ while(true){
+ buffer_capacity = incbuffer((char **)&buffer.data,
+ (size_t)buffer.size,
+ (size_t)buffer_capacity);
+ if(buffer_capacity == 0){
+ perror_plus("incbuffer");
+ free(buffer.data);
+ buffer.data = NULL;
+ break;
+ }
+ ssize_t bytes_read = read(secfile,
+ buffer.data + buffer.size,
+ BUFFER_SIZE);
+ /* EOF */
+ if(bytes_read == 0){
+ break;
+ }
+ /* check bytes_read for failure */
+ if(bytes_read < 0){
+ perror_plus("read");
+ free(buffer.data);
+ buffer.data = NULL;
+ break;
+ }
+ buffer.size += (unsigned int)bytes_read;
+ }
+ close(secfile);
+ } while(false);
+ /* If successful, use buffer to parse private key */
+ gnutls_sec_param_t sec_param = GNUTLS_SEC_PARAM_ULTRA;
+ if(buffer.data != NULL){
+ {
+ gnutls_openpgp_privkey_t privkey = NULL;
+ ret = gnutls_openpgp_privkey_init(&privkey);
if(ret != GNUTLS_E_SUCCESS){
- fprintf_plus(stderr, "Error importing OpenPGP key : %s",
+ fprintf_plus(stderr, "Error initializing OpenPGP key"
+ " structure: %s",
safer_gnutls_strerror(ret));
- privkey = NULL;
+ free(buffer.data);
+ buffer.data = NULL;
+ } else {
+ ret = gnutls_openpgp_privkey_import
+ (privkey, &buffer, GNUTLS_OPENPGP_FMT_BASE64, "", 0);
+ if(ret != GNUTLS_E_SUCCESS){
+ fprintf_plus(stderr, "Error importing OpenPGP key : %s",
+ safer_gnutls_strerror(ret));
+ privkey = NULL;
+ }
+ free(buffer.data);
+ buffer.data = NULL;
+ if(privkey != NULL){
+ /* Use private key to suggest an appropriate
+ sec_param */
+ sec_param = gnutls_openpgp_privkey_sec_param(privkey);
+ gnutls_openpgp_privkey_deinit(privkey);
+ if(debug){
+ fprintf_plus(stderr, "This OpenPGP key implies using"
+ " a GnuTLS security parameter \"%s\".\n",
+ safe_string(gnutls_sec_param_get_name
+ (sec_param)));
+ }
+ }
}
- free(buffer.data);
- buffer.data = NULL;
- if(privkey != NULL){
- /* Use private key to suggest an appropriate sec_param */
- sec_param = gnutls_openpgp_privkey_sec_param(privkey);
- gnutls_openpgp_privkey_deinit(privkey);
- if(debug){
- fprintf_plus(stderr, "This OpenPGP key implies using a"
- " GnuTLS security parameter \"%s\".\n",
- safe_string(gnutls_sec_param_get_name
- (sec_param)));
- }
+ }
+ if(sec_param == GNUTLS_SEC_PARAM_UNKNOWN){
+ /* Err on the side of caution */
+ sec_param = GNUTLS_SEC_PARAM_ULTRA;
+ if(debug){
+ fprintf_plus(stderr, "Falling back to security parameter"
+ " \"%s\"\n",
+ safe_string(gnutls_sec_param_get_name
+ (sec_param)));
}
}
}
- if(sec_param == GNUTLS_SEC_PARAM_UNKNOWN){
- /* Err on the side of caution */
- sec_param = GNUTLS_SEC_PARAM_ULTRA;
+ uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
+ if(uret != 0){
+ mc->dh_bits = uret;
if(debug){
- fprintf_plus(stderr, "Falling back to security parameter"
- " \"%s\"\n",
+ fprintf_plus(stderr, "A \"%s\" GnuTLS security parameter"
+ " implies %u DH bits; using that.\n",
safe_string(gnutls_sec_param_get_name
- (sec_param)));
+ (sec_param)),
+ mc->dh_bits);
}
- }
- }
- uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
- if(uret != 0){
- mc->dh_bits = uret;
- if(debug){
- fprintf_plus(stderr, "A \"%s\" GnuTLS security parameter"
- " implies %u DH bits; using that.\n",
+ } else {
+ fprintf_plus(stderr, "Failed to get implied number of DH"
+ " bits for security parameter \"%s\"): %s\n",
safe_string(gnutls_sec_param_get_name
(sec_param)),
- mc->dh_bits);
+ safer_gnutls_strerror(ret));
+ goto globalfail;
}
- } else {
- fprintf_plus(stderr, "Failed to get implied number of DH"
- " bits for security parameter \"%s\"): %s\n",
- safe_string(gnutls_sec_param_get_name(sec_param)),
+ } else if(debug){
+ fprintf_plus(stderr, "DH bits explicitly set to %u\n",
+ mc->dh_bits);
+ }
+ ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
+ if(ret != GNUTLS_E_SUCCESS){
+ fprintf_plus(stderr, "Error in GnuTLS prime generation (%u"
+ " bits): %s\n", mc->dh_bits,
safer_gnutls_strerror(ret));
goto globalfail;
}
- } else if(debug){
- fprintf_plus(stderr, "DH bits explicitly set to %u\n",
- mc->dh_bits);
- }
- ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
- if(ret != GNUTLS_E_SUCCESS){
- fprintf_plus(stderr, "Error in GnuTLS prime generation (%u bits):"
- " %s\n", mc->dh_bits, safer_gnutls_strerror(ret));
- goto globalfail;
- }
-
+ }
gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
return 0;
@@ -748,8 +813,6 @@
/* ignore client certificate if any. */
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
- gnutls_dh_set_prime_bits(*session, mc->dh_bits);
-
return 0;
}
@@ -2240,6 +2303,7 @@
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
const char *seckey = PATHDIR "/" SECKEY;
const char *pubkey = PATHDIR "/" PUBKEY;
+ const char *dh_params_file = NULL;
char *interfaces_hooks = NULL;
bool gnutls_initialized = false;
@@ -2298,6 +2362,11 @@
.doc = "Bit length of the prime number used in the"
" Diffie-Hellman key exchange",
.group = 2 },
+ { .name = "dh-params", .key = 134,
+ .arg = "FILE",
+ .doc = "PEM-encoded PKCS#3 file with pre-generated parameters"
+ " for the Diffie-Hellman key exchange",
+ .group = 2 },
{ .name = "priority", .key = 130,
.arg = "STRING",
.doc = "GnuTLS priority string for the TLS handshake",
@@ -2358,6 +2427,9 @@
}
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
break;
+ case 134: /* --dh-params */
+ dh_params_file = arg;
+ break;
case 130: /* --priority */
mc.priority = arg;
break;
@@ -2682,7 +2754,7 @@
goto end;
}
- ret = init_gnutls_global(pubkey, seckey, &mc);
+ ret = init_gnutls_global(pubkey, seckey, dh_params_file, &mc);
if(ret == -1){
fprintf_plus(stderr, "init_gnutls_global failed\n");
exitcode = EX_UNAVAILABLE;
=== modified file 'plugins.d/mandos-client.xml'
--- plugins.d/mandos-client.xml 2015-07-06 20:29:34 +0000
+++ plugins.d/mandos-client.xml 2015-07-08 21:18:49 +0000
@@ -2,7 +2,7 @@
-
+
%common;
]>
@@ -99,6 +99,10 @@
+
+
+
+
@@ -313,7 +317,26 @@
Sets the number of bits to use for the prime number in the
TLS Diffie-Hellman key exchange. The default value is
- selected automatically based on the OpenPGP key.
+ selected automatically based on the OpenPGP key. Note
+ that if the option is used,
+ the values from that file will be used instead.
+
+
+
+
+
+
+
+
+ Specifies a PEM-encoded PKCS#3 file to read the parameters
+ needed by the TLS Diffie-Hellman key exchange from. If
+ this option is not given, or if the file for some reason
+ could not be used, the parameters will be generated on
+ startup, which will take some time and processing power.
+ Those using servers running under time, power or processor
+ constraints may want to generate such a file in advance
+ and use this option.