2
* Program to generate MD5 and RSA keys for NTP clients and servers
10
#include <netinfo/ni.h>
14
#include "ntp_stdlib.h"
15
#include "ntp_string.h"
16
#include "ntp_filegen.h"
17
#include "ntp_unixtime.h"
18
#include "ntp_config.h"
19
#include "ntp_cmdargs.h"
23
#include <limits.h> /* PATH_MAX */
27
# include "ntp_crypto.h"
31
# ifdef _POSIX_PATH_MAX
32
# define PATH_MAX _POSIX_PATH_MAX
41
#define MAXKEYLEN 1024 /* maximum encoded key length */
42
#define MODULUSLEN 512 /* length of RSA modulus */
43
#define PRIMELEN 512 /* length of D_H prime, generator */
46
* This program generates (up to) four files:
48
* ntp.keys containing the DES/MD5 private keys,
49
* ntpkey containing the RSA private key,
50
* ntpkey_HOST containing the RSA public key
51
* where HOST is the DNS name of the generating machine,
52
* ntpkey_dh containing the parameters for the Diffie-Hellman
53
* key-agreement algorithm.
55
* The files contain cryptographic values generated by the algorithms of
56
* the rsaref20 package and are in printable ASCII format. Since the
57
* algorythms are seeded by the system clock, each run of this program
58
* will produce a different outcome. There are no options or frills of
59
* any sort, although a number of options would seem to be appropriate.
60
* Waving this program in the breeze will no doubt bring a cast of
61
* thousands to wiggle the options this way and that for various useful
64
* The names of all files begin with "ntp" and end with an extension
65
* consisting of the seconds value of the current NTP timestamp, which
66
* appears in the form ".*". This provides a way to distinguish between
67
* key generations, since the host name and timestamp can be fetched by
68
* a client during operation.
70
* The ntp.keys.* file contains 16 MD5 keys. Each key consists of 16
71
* characters randomized over the ASCII 95-character printing subset.
72
* The file is read by the daemon at the location specified by the keys
73
* configuration file command and made visible only to root. An
74
* additional key consisting of a easily remembered password should be
75
* added by hand for use with the ntpdc program. The file must be
76
* distributed by secure means to other servers and clients sharing the
77
* same security compartment.
79
* The key identifiers for MD5 and DES keys must be less than 65536,
80
* although this program uses only the identifiers from 1 to 16. The key
81
* identifier for each association is specified as the key argument in
82
* the server or peer configuration file command.
84
* The ntpkey.* file contains the RSA private key. It is read by the
85
* daemon at the location specified by the private argument of the
86
* crypto configuration file command and made visible only to root.
87
* This file is useful only to the machine that generated it and never
88
* shared with any other daemon or application program.
90
* The ntpkey_host.* file contains the RSA public key, where host is the
91
* DNS name of the host that generated it. The file is read by the
92
* daemon at the location specified by the public argument to the server
93
* or peer configuration file command. This file can be widely
94
* distributed and stored without using secure means, since the data are
97
* The ntp_dh.* file contains two Diffie-Hellman parameters, the prime
98
* modulus and the generator. The file is read by the daemon at the
99
* location specified by the dhparams argument of the crypto
100
* configuration file command. This file can be widely distributed and
101
* stored without using secure means, since the data are public values.
103
* The file formats all begin with two lines. The first line contains
104
* the file name and decimal timestamp, while the second contains the
105
* readable datestamp. Lines beginning with # are considered comments
106
* and ignored by the daemon. In the ntp.keys.* file, the next 16 lines
107
* contain the MD5 keys in order. In the ntpkey.* and ntpkey_host.*
108
* files, the next line contains the modulus length in bits followed by
109
* the key as a PEM encoded string. In the ntpkey_dh.* file, the next
110
* line contains the prime length in bytes followed by the prime as a
111
* PEM encoded string, and the next and final line contains the
112
* generator length in bytes followed by the generator as a PEM encoded
115
* Note: See the file ./source/rsaref.h in the rsaref20 package for
116
* explanation of return values, if necessary.
120
extern char *config_file;
123
extern struct netinfo_config_state *config_netinfo;
124
extern int check_netinfo;
125
#endif /* HAVE_NETINFO */
128
char *alt_config_file;
130
char config_file_storage[PATH_MAX];
131
char alt_config_file_storage[PATH_MAX];
132
#endif /* SYS_WINNT */
134
int make_dh = 0; /* Make D-H parameter file? */
135
int make_md5 = 0; /* Make MD5 keyfile? */
136
int make_rsa = 0; /* Make RSA pair? */
137
int force = 0; /* Force the installation? */
138
int here = 0; /* Put the files here (curdir)? */
139
int nosymlinks = 0; /* Just create the (timestamped) files? */
140
int memorex = 0; /* Are we live? */
141
int trash = 0; /* Trash old files? */
144
char *f1_keysdir = NTP_KEYSDIR;
146
char *f1_keys; /* Visible MD5 key file name */
147
char *f2_keys; /* timestamped */
148
char *f3_keys; /* previous filename */
163
/* Stubs and hacks so we can link with ntp_config.o */
164
u_long sys_automax; /* maximum session key lifetime */
165
int sys_bclient; /* we set our time to broadcasts */
166
int sys_manycastserver; /* 1 => respond to manycast client pkts */
167
u_long client_limit_period;
168
char * req_file; /* name of the file with configuration info */
169
keyid_t ctl_auth_keyid; /* keyid used for authenticating write requests */
170
struct interface *any_interface; /* default interface */
171
keyid_t info_auth_keyid; /* keyid used to authenticate requests */
172
u_long current_time; /* current time (s) */
173
const char *Version = ""; /* version declaration */
174
keyid_t req_keyid; /* request keyid */
176
u_long client_limit_period;
178
u_long sys_revoke; /* keys revoke timeout */
179
volatile int debug = 0; /* debugging flag */
180
u_char sys_minpoll; /* min poll interval (log2 s) */
182
void snifflink P((const char *, char **));
183
int filep P((const char *));
184
FILE *newfile P((const char *, const char *, mode_t, const char *));
185
void cleanlinks P((const char *, const char *, const char *));
189
struct sockaddr_in *srcadr,
190
struct interface *dstadr,
201
if (debug > 1) printf("peer_config...\n");
213
if (debug > 1) printf("set_sys_var...\n");
221
if (debug > 1) printf("ntp_intres...\n");
228
struct sockaddr_in *raddr,
229
struct interface *linter,
234
if (debug > 1) printf("ctlsettrap...\n");
242
int item, /* configuration item */
243
char *cp /* file name */
248
if (debug > 0) printf("crypto_config: DH/<%d> <%s>\n", item, cp);
249
f1_dhparms = strdup(cp);
251
case CRYPTO_CONF_PRIV:
252
if (debug > 0) printf("crypto_config: PRIVATEKEY/<%d> <%s>\n", item, cp);
253
f1_privatekey = strdup(cp);
255
case CRYPTO_CONF_PUBL:
256
if (debug > 0) printf("crypto_config: PUBLICKEY/<%d> <%s>\n", item, cp);
257
f1_publickey = strdup(cp);
260
if (debug > 1) printf("crypto_config: <%d> <%s>\n", item, cp);
270
struct sockaddr_in *addr
273
if (debug > 1) printf("findinterface...\n");
280
struct sockaddr_in *srcadr,
281
struct refclockstat *in,
282
struct refclockstat *out
285
if (debug > 1) printf("refclock_control...\n");
296
if (debug > 1) printf("loop_config...\n");
309
if (debug > 1) printf("filegen_config...\n");
317
char *invalue /* only one type so far */
320
if (debug > 1) printf("stats_config...\n");
328
struct sockaddr_in *resaddr,
329
struct sockaddr_in *resmask,
334
if (debug > 1) printf("hack_restrict...\n");
342
if (debug > 1) printf("kill_asyncio...\n");
354
if (debug > 1) printf("proto_config...\n");
363
if (debug > 0) printf("getauthkeys: got <%s>\n", keyfile);
364
f1_keys = strdup(keyfile);
374
if (debug > 1) printf("filegen_get...\n");
379
/* End of stubs and hacks */
387
printf("Usage: %s [ -c ntp.conf ] [ -g {d,m,r} ] [ -k key_file ]\n",
389
printf(" [ -d ] [ -f ] [ -h ] [ -l ] [ -n ] [ -t ]\n");
391
printf(" -c /etc/ntp.conf Location of ntp.conf file\n");
392
printf(" -d enable debug messages (can be used multiple times)\n");
393
printf(" -f force installation of generated keys.\n");
394
printf(" -g d Generate D-H parameter file\n");
395
printf(" -g m Generate MD5 key file\n");
396
printf(" -g r Generate RSA keys\n");
397
printf(" -g dmr (Can be combined)\n");
398
printf(" -h Build keys here (current directory). Implies -l\n");
399
printf(" -k key_file Location of key file\n");
400
printf(" -l Don't make the symlinks\n");
401
printf(" -n Don't actually do anything, just say what would be done\n");
402
printf(" -t Trash the (old) files at the end of symlink\n");
416
while ((i = ntp_getopt(argc, argv, "c:dfg:hlnt")) != EOF)
419
config_file = ntp_optarg;
431
while (*ntp_optarg) {
432
switch (*ntp_optarg) {
470
/* If no file type was specified, make them all. */
471
if (!(make_dh | make_md5 | make_rsa)) {
492
rc = readlink(file, buf, sizeof buf);
495
case EINVAL: /* Fall thru */
499
fprintf(stderr, "%s: readlink(%s) failed: (%d) %s\n",
500
progname, file, errno, strerror(errno));
504
*linkdata = strdup(buf);
505
/* XXX: make sure linkdata is not 0... */
506
#endif /* not HAVE_READLINK */
518
if (-1 == stat(fn, &sb)) {
521
fprintf(stderr, "stat(%s) failed: %s\n",
522
fn, strerror(errno));
531
const char *f1, /* Visible file */
532
const char *f2, /* New timestamped file name */
533
mode_t fmask, /* umask for new timestamped file */
534
const char *f3 /* Previous symlink target */
541
if (debug > 1) printf("newfile(%s,%s,%0o,%s)\n", f1, f2,
542
(unsigned)fmask, f3 ? f3 : "NULL");
545
- no symlink support, or
546
- there is no old symlink (!f3)
547
- - file = dirname(f1) / f2
550
- - file = dirname(f3) / f2
552
- - file = dirname(f1) / dirname(f3) / f2
554
print any error message/bail
559
snprintf(fb, sizeof fb, "%s", f2);
568
/* file = dirname(f1) / f2 */
569
snprintf(fb, sizeof fb, "%s", f1);
570
cp = strrchr(fb, '/');
574
snprintf(fb, sizeof fb, "%s/%s", fb, f2);
575
if (debug > 1) printf("case 1: file is <%s>\n", fb);
579
- - file = dirname(f3) / f2
581
- - file = dirname(f1) / dirname(f3) / f2
584
snprintf(fb, sizeof fb, "%s", f1);
585
cp = strrchr(fb, '/');
591
printf("case 2: file is <%s>\n", fb);
595
snprintf(fb, sizeof fb, "%s%s", fb, f3);
596
cp = strrchr(fb, '/');
600
snprintf(fb, sizeof fb, "%s/%s", fb, f2);
601
if (debug > 1) printf("case 3: file is <%s>\n", fb);
607
print any error message/bail
611
printf("Would write file <%s>\n", fb);
616
omask = umask(fmask);
629
const char *f1, /* Visible file */
630
const char *f2, /* New timestamped file name */
631
const char *f3 /* Previous symlink target */
639
Just return if nosymlinks.
641
file = dirname(f3) / f2
644
- if f3 begins with a /, unlink it
645
- else, unlink dirname(f1) / f3
647
#endif /* HAVE_READLINK */
653
printf("Would unlink(%s)\n", f1);
654
else if (unlink(f1)) {
655
if (errno != ENOENT) {
656
fprintf(stderr, "unlink(%s) failed: %s\n", f1,
661
/* file = dirname(f3) / f2 */
663
snprintf(fb, sizeof fb, "%s", f3);
664
cp = strrchr(fb, '/');
674
snprintf(fb, sizeof fb, "%s%s", fb, f2);
675
if (debug > 1) printf("cleanlinks 1: file is <%s>\n", fb);
678
printf("Would symlink <%s> -> <%s>\n", f1, fb);
679
else if (symlink(fb, f1)) {
680
fprintf(stderr, "symlink(%s,%s) failed: %s\n", fb, f1,
687
- if f3 begins with a /, unlink it
688
- else, unlink dirname(f1) / f3
693
printf("Would unlink(%s)\n", f3);
694
else if (unlink(f3)) {
695
if (errno != ENOENT) {
696
fprintf(stderr, "unlink(%s) failed: %s\n", f3,
702
snprintf(fb, sizeof fb, "%s", f1);
703
cp = strrchr(fb, '/');
707
snprintf(fb, sizeof fb, "%s/%s", fb, f3);
709
printf("cleanlinks 2: file is <%s>\n", fb);
711
printf("Would unlink(%s)\n", fb);
712
else if (unlink(fb)) {
713
if (errno != ENOENT) {
714
fprintf(stderr, "unlink(%s) failed: %s\n", fb,
733
R_RSA_PRIVATE_KEY rsaref_private; /* RSA private key */
734
R_RSA_PUBLIC_KEY rsaref_public; /* RSA public key */
735
R_RSA_PROTO_KEY protokey; /* RSA prototype key */
736
R_DH_PARAMS dh_params; /* Diffie-Hellman parameters */
737
R_RANDOM_STRUCT randomstr; /* random structure */
738
int rval; /* return value */
739
u_char encoded_key[MAXKEYLEN]; /* encoded PEM string buffer */
740
u_int modulus; /* modulus length */
743
struct timeval tv; /* initialization vector */
744
u_long ntptime; /* NTP timestamp */
745
char hostname[256]; /* DNS host name */
746
u_char md5key[17]; /* generated MD5 key */
747
FILE *str; /* file handle */
750
mode_t std_mask; /* Standard mask */
751
mode_t sec_mask = 077; /* Secure mask */
752
char pathbuf[PATH_MAX];
754
gethostname(hostname, sizeof(hostname));
755
gettimeofday(&tv, 0);
756
ntptime = tv.tv_sec + JAN_1970;
758
/* Initialize config_file */
759
getconfig(argc, argv); /* ntpd/ntp_config.c */
762
/* Shouldn't happen... */
763
f1_keysdir = "PATH_KEYSDIR";
765
if (*f1_keysdir != '/') {
767
"%s: keysdir path <%s> doesn't begin with a /\n",
768
progname, f1_keysdir);
773
snprintf(pathbuf, sizeof pathbuf, "ntp.keys.%lu",
775
f2_keys = strdup(pathbuf);
778
snprintf(pathbuf, sizeof pathbuf, "%s/ntp.keys",
780
f1_keys = strdup(pathbuf);
782
if (*f1_keys != '/') {
784
"%s: keys path <%s> doesn't begin with a /\n",
788
snifflink(f1_keys, &f3_keys);
791
snprintf(pathbuf, sizeof pathbuf, "ntpkey_%s.%lu",
793
f2_publickey = strdup(pathbuf);
796
snprintf(pathbuf, sizeof pathbuf, "%s/ntpkey_%s",
797
f1_keysdir, hostname);
798
f1_publickey = strdup(pathbuf);
800
if (*f1_publickey != '/') {
802
"%s: publickey path <%s> doesn't begin with a /\n",
803
progname, f1_publickey);
806
snifflink(f1_publickey, &f3_publickey);
808
if (!f2_privatekey) {
809
snprintf(pathbuf, sizeof pathbuf, "ntpkey.%lu",
811
f2_privatekey = strdup(pathbuf);
813
if (!f1_privatekey) {
814
snprintf(pathbuf, sizeof pathbuf, "%s/ntpkey",
816
f1_privatekey = strdup(pathbuf);
818
if (*f1_privatekey != '/') {
820
"%s: privatekey path <%s> doesn't begin with a /\n",
821
progname, f1_privatekey);
824
snifflink(f1_privatekey, &f3_privatekey);
827
snprintf(pathbuf, sizeof pathbuf, "ntpkey_dh.%lu",
829
f2_dhparms = strdup(pathbuf);
832
snprintf(pathbuf, sizeof pathbuf, "%s/ntpkey_dh",
834
f1_dhparms = strdup(pathbuf);
836
if (*f1_dhparms != '/') {
838
"%s: dhparms path <%s> doesn't begin with a /\n",
839
progname, f1_dhparms);
842
snifflink(f1_dhparms, &f3_dhparms);
845
printf("After config:\n");
846
printf("keysdir = <%s>\n", f1_keysdir? f1_keysdir: "");
847
printf("keys = <%s> -> <%s>\n"
848
, f1_keys? f1_keys: ""
849
, f2_keys? f2_keys: ""
851
printf(" old = <%s>\n", f3_keys? f3_keys: "");
852
printf("publickey = <%s> -> <%s>\n"
853
, f1_publickey? f1_publickey: ""
854
, f2_publickey? f2_publickey: ""
856
printf(" old = <%s>\n", f3_publickey? f3_publickey: "");
857
printf("privatekey = <%s> -> <%s>\n"
858
, f1_privatekey? f1_privatekey: ""
859
, f2_privatekey? f2_privatekey: ""
861
printf(" old = <%s>\n", f3_privatekey? f3_privatekey: "");
862
printf("dhparms = <%s> -> <%s>\n"
863
, f1_dhparms? f1_dhparms: ""
864
, f2_dhparms? f2_dhparms: ""
866
printf(" old = <%s>\n", f3_dhparms? f3_dhparms: "");
870
for each file we're going to install:
871
- make the new timestamped file
873
- - remove any old link
876
- - - remove the old file
879
std_mask = umask(sec_mask); /* Get the standard mask */
880
(void) umask(std_mask);
882
if (make_md5 && (force || !filep(f1_keys))) {
884
* Generate 16 random MD5 keys.
886
printf("Generating MD5 key file...\n");
887
str = newfile(f1_keys, f2_keys, sec_mask, f3_keys);
889
srandom((u_int)tv.tv_usec);
890
fprintf(str, "# MD5 key file %s\n# %s", f2_keys,
891
ctime((const time_t *) &tv.tv_sec));
892
for (i = 1; i <= 16; i++) {
893
for (j = 0; j < 16; j++) {
895
temp = random() & 0xff;
897
** Harlan says Karnaugh maps
898
** are not his friend, and
899
** compilers can optimize
904
if (temp > 0x20 && temp < 0x7f)
907
md5key[j] = (u_char)temp;
910
fprintf(str, "%2d M %16s # MD5 key\n",
914
if (str) fclose(str);
915
cleanlinks(f1_keys, f2_keys, f3_keys);
919
if (make_rsa && (force || !filep(f1_publickey)
920
|| !filep(f1_privatekey))) {
922
* Roll the RSA public/private key pair.
924
printf("Generating RSA public/private key pair (%d bits)...\n",
927
protokey.bits = MODULUSLEN;
928
protokey.useFermat4 = 1;
929
R_RandomInit(&randomstr);
930
R_GetRandomBytesNeeded(&len, &randomstr);
931
for (i = 0; i < len; i++) {
933
R_RandomUpdate(&randomstr, (u_char *)&temp, 1);
935
rval = R_GeneratePEMKeys(&rsaref_public,
936
&rsaref_private, &protokey,
939
printf("R_GeneratePEMKeys error %x\n", rval);
945
* Generate the file "ntpkey.*" containing the RSA
946
* private key in printable ASCII format.
948
str = newfile(f1_privatekey, f2_privatekey, sec_mask,
951
len = sizeof(rsaref_private)
952
- sizeof(rsaref_private.bits);
953
modulus = (u_int32)rsaref_private.bits;
954
fprintf(str, "# RSA private key file %s\n# %s",
955
f2_privatekey, ctime(&tv.tv_sec));
956
R_EncodePEMBlock(encoded_key, &temp,
957
(u_char *)rsaref_private.modulus,
959
encoded_key[temp] = '\0';
960
fprintf(str, "%d %s\n", modulus, encoded_key);
962
if (str) fclose(str);
963
cleanlinks(f1_privatekey, f2_privatekey, f3_privatekey);
966
* Generate the file "ntpkey_host.*" containing the RSA
967
* public key in printable ASCII format.
969
str = newfile(f1_publickey, f2_publickey, std_mask,
972
len = sizeof(rsaref_public)
973
- sizeof(rsaref_public.bits);
974
modulus = (u_int32)rsaref_public.bits;
975
fprintf(str, "# RSA public key file %s\n# %s",
976
f2_publickey, ctime(&tv.tv_sec));
977
R_EncodePEMBlock(encoded_key, &temp,
978
(u_char *)rsaref_public.modulus, len);
979
encoded_key[temp] = '\0';
980
fprintf(str, "%d %s\n", modulus, encoded_key);
982
if (str) fclose(str);
983
cleanlinks(f1_publickey, f2_publickey, f3_publickey);
988
if (make_dh && (force || !filep(f1_dhparms))) {
990
* Roll the prime and generator for the Diffie-Hellman key
991
* agreement algorithm.
993
printf("Generating Diffie-Hellman parameters (%d bits)...\n",
995
str = newfile(f1_dhparms, f2_dhparms, std_mask, f3_dhparms);
998
R_RandomInit(&randomstr);
999
R_GetRandomBytesNeeded(&len, &randomstr);
1000
for (i = 0; i < len; i++) {
1002
R_RandomUpdate(&randomstr, (u_char *)&temp, 1);
1006
* Generate the file "ntpkey_dh.*" containing the
1007
* Diffie-Hellman prime and generator in printable
1010
len = DH_PRIME_LEN(PRIMELEN);
1011
dh_params.prime = (u_char *)malloc(len);
1012
dh_params.generator = (u_char *)malloc(len);
1013
rval = R_GenerateDHParams(&dh_params, PRIMELEN,
1014
PRIMELEN / 2, &randomstr);
1016
printf("R_GenerateDHParams error %x\n", rval);
1021
"# Diffie-Hellman parameter file %s\n# %s",
1022
f2_dhparms, ctime(&tv.tv_sec));
1023
R_EncodePEMBlock(encoded_key, &temp,
1024
(u_char *)dh_params.prime,
1025
dh_params.primeLen);
1026
encoded_key[temp] = '\0';
1027
fprintf(str, "%d %s\n", dh_params.primeLen,
1029
R_EncodePEMBlock(encoded_key, &temp,
1030
(u_char *)dh_params.generator,
1031
dh_params.generatorLen);
1032
encoded_key[temp] = '\0';
1033
fprintf(str, "%d %s\n", dh_params.generatorLen,
1036
if (str) fclose(str);
1037
cleanlinks(f1_dhparms, f2_dhparms, f3_dhparms);