xref: /freebsd/contrib/ntp/util/ntp-keygen.c (revision 5e91a9b70066bc508b15c00dfc060d5261757edf)
19c2daa00SOllivier Robert /*
29c2daa00SOllivier Robert  * Program to generate cryptographic keys for NTP clients and servers
39c2daa00SOllivier Robert  *
49c2daa00SOllivier Robert  * This program generates files "ntpkey_<type>_<hostname>.<filestamp>",
59c2daa00SOllivier Robert  * where <type> is the file type, <hostname> is the generating host and
69c2daa00SOllivier Robert  * <filestamp> is the NTP seconds in decimal format. The NTP programs
79c2daa00SOllivier Robert  * expect generic names such as "ntpkey_<type>_whimsy.udel.edu" with the
89c2daa00SOllivier Robert  * association maintained by soft links.
99c2daa00SOllivier Robert  *
109c2daa00SOllivier Robert  * Files are prefixed with a header giving the name and date of creation
119c2daa00SOllivier Robert  * followed by a type-specific descriptive label and PEM-encoded data
129c2daa00SOllivier Robert  * string compatible with programs of the OpenSSL library.
139c2daa00SOllivier Robert  *
149c2daa00SOllivier Robert  * Note that private keys can be password encrypted as per OpenSSL
159c2daa00SOllivier Robert  * conventions.
169c2daa00SOllivier Robert  *
179c2daa00SOllivier Robert  * The file types include
189c2daa00SOllivier Robert  *
199c2daa00SOllivier Robert  * ntpkey_MD5key_<hostname>.<filestamp>
209c2daa00SOllivier Robert  * 	MD5 (128-bit) keys used to compute message digests in symmetric
219c2daa00SOllivier Robert  *	key cryptography
229c2daa00SOllivier Robert  *
239c2daa00SOllivier Robert  * ntpkey_RSAkey_<hostname>.<filestamp>
249c2daa00SOllivier Robert  * ntpkey_host_<hostname> (RSA) link
259c2daa00SOllivier Robert  *	RSA private/public host key pair used for public key signatures
269c2daa00SOllivier Robert  *	and data encryption
279c2daa00SOllivier Robert  *
289c2daa00SOllivier Robert  * ntpkey_DSAkey_<hostname>.<filestamp>
299c2daa00SOllivier Robert  * ntpkey_sign_<hostname> (RSA or DSA) link
309c2daa00SOllivier Robert  *	DSA private/public sign key pair used for public key signatures,
319c2daa00SOllivier Robert  *	but not data encryption
329c2daa00SOllivier Robert  *
339c2daa00SOllivier Robert  * ntpkey_IFFpar_<hostname>.<filestamp>
349c2daa00SOllivier Robert  * ntpkey_iff_<hostname> (IFF server/client) link
359c2daa00SOllivier Robert  * ntpkey_iffkey_<hostname> (IFF client) link
369c2daa00SOllivier Robert  *	Schnorr (IFF) server/client identity parameters
379c2daa00SOllivier Robert  *
389c2daa00SOllivier Robert  * ntpkey_IFFkey_<hostname>.<filestamp>
399c2daa00SOllivier Robert  *	Schnorr (IFF) client identity parameters
409c2daa00SOllivier Robert  *
419c2daa00SOllivier Robert  * ntpkey_GQpar_<hostname>.<filestamp>,
429c2daa00SOllivier Robert  * ntpkey_gq_<hostname> (GQ) link
439c2daa00SOllivier Robert  *	Guillou-Quisquater (GQ) identity parameters
449c2daa00SOllivier Robert  *
459c2daa00SOllivier Robert  * ntpkey_MVpar_<hostname>.<filestamp>,
469c2daa00SOllivier Robert  *	Mu-Varadharajan (MV) server identity parameters
479c2daa00SOllivier Robert  *
489c2daa00SOllivier Robert  * ntpkey_MVkeyX_<hostname>.<filestamp>,
499c2daa00SOllivier Robert  * ntpkey_mv_<hostname> (MV server) link
509c2daa00SOllivier Robert  * ntpkey_mvkey_<hostname> (MV client) link
519c2daa00SOllivier Robert  *	Mu-Varadharajan (MV) client identity parameters
529c2daa00SOllivier Robert  *
539c2daa00SOllivier Robert  * ntpkey_XXXcert_<hostname>.<filestamp>
549c2daa00SOllivier Robert  * ntpkey_cert_<hostname> (RSA or DSA) link
559c2daa00SOllivier Robert  *	X509v3 certificate using RSA or DSA public keys and signatures.
569c2daa00SOllivier Robert  *	XXX is a code identifying the message digest and signature
579c2daa00SOllivier Robert  *	encryption algorithm
589c2daa00SOllivier Robert  *
599c2daa00SOllivier Robert  * Available digest/signature schemes
609c2daa00SOllivier Robert  *
619c2daa00SOllivier Robert  * RSA:	RSA-MD2, RSA-MD5, RSA-SHA, RSA-SHA1, RSA-MDC2, EVP-RIPEMD160
629c2daa00SOllivier Robert  * DSA:	DSA-SHA, DSA-SHA1
639c2daa00SOllivier Robert  *
649c2daa00SOllivier Robert  * Note: Once in a while because of some statistical fluke this program
659c2daa00SOllivier Robert  * fails to generate and verify some cryptographic data, as indicated by
669c2daa00SOllivier Robert  * exit status -1. In this case simply run the program again. If the
679c2daa00SOllivier Robert  * program does complete with return code 0, the data are correct as
689c2daa00SOllivier Robert  * verified.
699c2daa00SOllivier Robert  *
709c2daa00SOllivier Robert  * These cryptographic routines are characterized by the prime modulus
719c2daa00SOllivier Robert  * size in bits. The default value of 512 bits is a compromise between
729c2daa00SOllivier Robert  * cryptographic strength and computing time and is ordinarily
739c2daa00SOllivier Robert  * considered adequate for this application. The routines have been
749c2daa00SOllivier Robert  * tested with sizes of 256, 512, 1024 and 2048 bits. Not all message
759c2daa00SOllivier Robert  * digest and signature encryption schemes work with sizes less than 512
769c2daa00SOllivier Robert  * bits. The computing time for sizes greater than 2048 bits is
779c2daa00SOllivier Robert  * prohibitive on all but the fastest processors. An UltraSPARC Blade
789c2daa00SOllivier Robert  * 1000 took something over nine minutes to generate and verify the
799c2daa00SOllivier Robert  * values with size 2048. An old SPARC IPC would take a week.
809c2daa00SOllivier Robert  *
819c2daa00SOllivier Robert  * The OpenSSL library used by this program expects a random seed file.
829c2daa00SOllivier Robert  * As described in the OpenSSL documentation, the file name defaults to
839c2daa00SOllivier Robert  * first the RANDFILE environment variable in the user's home directory
849c2daa00SOllivier Robert  * and then .rnd in the user's home directory.
859c2daa00SOllivier Robert  */
869c2daa00SOllivier Robert #ifdef HAVE_CONFIG_H
879c2daa00SOllivier Robert # include <config.h>
889c2daa00SOllivier Robert #endif
899c2daa00SOllivier Robert #include <string.h>
909c2daa00SOllivier Robert #include <stdio.h>
919c2daa00SOllivier Robert #include <stdlib.h>
929c2daa00SOllivier Robert #include <unistd.h>
939c2daa00SOllivier Robert #include <sys/stat.h>
949c2daa00SOllivier Robert #include <sys/time.h>
959c2daa00SOllivier Robert #if HAVE_SYS_TYPES_H
969c2daa00SOllivier Robert # include <sys/types.h>
979c2daa00SOllivier Robert #endif
989c2daa00SOllivier Robert #include "ntp_types.h"
999c2daa00SOllivier Robert #include "l_stdlib.h"
1009c2daa00SOllivier Robert 
1019c2daa00SOllivier Robert #ifdef SYS_WINNT
1029c2daa00SOllivier Robert extern	int	ntp_getopt	P((int, char **, const char *));
1039c2daa00SOllivier Robert #define getopt ntp_getopt
1049c2daa00SOllivier Robert #define optarg ntp_optarg
1059c2daa00SOllivier Robert #endif
1069c2daa00SOllivier Robert 
1079c2daa00SOllivier Robert #ifdef OPENSSL
1089c2daa00SOllivier Robert #include "openssl/bn.h"
1099c2daa00SOllivier Robert #include "openssl/evp.h"
1109c2daa00SOllivier Robert #include "openssl/err.h"
1119c2daa00SOllivier Robert #include "openssl/rand.h"
1129c2daa00SOllivier Robert #include "openssl/pem.h"
1139c2daa00SOllivier Robert #include "openssl/x509v3.h"
1149c2daa00SOllivier Robert #include <openssl/objects.h>
1159c2daa00SOllivier Robert #endif /* OPENSSL */
1169c2daa00SOllivier Robert 
1179c2daa00SOllivier Robert /*
1189c2daa00SOllivier Robert  * Cryptodefines
1199c2daa00SOllivier Robert  */
1209c2daa00SOllivier Robert #define	MD5KEYS		16	/* number of MD5 keys generated */
1219c2daa00SOllivier Robert #define	JAN_1970	ULONG_CONST(2208988800) /* NTP seconds */
1229c2daa00SOllivier Robert #define YEAR		((long)60*60*24*365) /* one year in seconds */
1239c2daa00SOllivier Robert #define MAXFILENAME	256	/* max file name length */
1249c2daa00SOllivier Robert #define MAXHOSTNAME	256	/* max host name length */
1259c2daa00SOllivier Robert #ifdef OPENSSL
1269c2daa00SOllivier Robert #define	PLEN		512	/* default prime modulus size (bits) */
1279c2daa00SOllivier Robert 
1289c2daa00SOllivier Robert /*
1299c2daa00SOllivier Robert  * Strings used in X509v3 extension fields
1309c2daa00SOllivier Robert  */
1319c2daa00SOllivier Robert #define KEY_USAGE		"digitalSignature,keyCertSign"
1329c2daa00SOllivier Robert #define BASIC_CONSTRAINTS	"critical,CA:TRUE"
1339c2daa00SOllivier Robert #define EXT_KEY_PRIVATE		"private"
1349c2daa00SOllivier Robert #define EXT_KEY_TRUST		"trustRoot"
1359c2daa00SOllivier Robert #endif /* OPENSSL */
1369c2daa00SOllivier Robert 
1379c2daa00SOllivier Robert /*
1389c2daa00SOllivier Robert  * Prototypes
1399c2daa00SOllivier Robert  */
1409c2daa00SOllivier Robert FILE	*fheader	P((const char *, const char *));
1419c2daa00SOllivier Robert void	fslink		P((const char *, const char *));
1429c2daa00SOllivier Robert int	gen_md5		P((char *));
1439c2daa00SOllivier Robert #ifdef OPENSSL
1449c2daa00SOllivier Robert EVP_PKEY *gen_rsa	P((char *));
1459c2daa00SOllivier Robert EVP_PKEY *gen_dsa	P((char *));
1469c2daa00SOllivier Robert EVP_PKEY *gen_iff	P((char *));
1479c2daa00SOllivier Robert EVP_PKEY *gen_gqpar	P((char *));
1489c2daa00SOllivier Robert EVP_PKEY *gen_gqkey	P((char *, EVP_PKEY *));
1499c2daa00SOllivier Robert EVP_PKEY *gen_mv	P((char *));
1509c2daa00SOllivier Robert int	x509		P((EVP_PKEY *, const EVP_MD *, char *, char *));
1519c2daa00SOllivier Robert void	cb		P((int, int, void *));
1529c2daa00SOllivier Robert EVP_PKEY *genkey	P((char *, char *));
1539c2daa00SOllivier Robert u_long	asn2ntp		P((ASN1_TIME *));
1549c2daa00SOllivier Robert #endif /* OPENSSL */
1559c2daa00SOllivier Robert 
1569c2daa00SOllivier Robert /*
1579c2daa00SOllivier Robert  * Program variables
1589c2daa00SOllivier Robert  */
1599c2daa00SOllivier Robert extern char *optarg;		/* command line argument */
1609c2daa00SOllivier Robert int	debug = 0;		/* debug, not de bug */
1619c2daa00SOllivier Robert int	rval;			/* return status */
1625e91a9b7SOllivier Robert #ifdef OPENSSL
1639c2daa00SOllivier Robert u_int	modulus = PLEN;		/* prime modulus size (bits) */
1645e91a9b7SOllivier Robert #endif
1659c2daa00SOllivier Robert int	nkeys = 0;		/* MV keys */
1669c2daa00SOllivier Robert time_t	epoch;			/* Unix epoch (seconds) since 1970 */
1679c2daa00SOllivier Robert char	*hostname;		/* host name (subject name) */
1689c2daa00SOllivier Robert char	*trustname;		/* trusted host name (issuer name) */
1699c2daa00SOllivier Robert char	filename[MAXFILENAME + 1]; /* file name */
1709c2daa00SOllivier Robert char	*passwd1 = NULL;	/* input private key password */
1719c2daa00SOllivier Robert char	*passwd2 = NULL;	/* output private key password */
1729c2daa00SOllivier Robert #ifdef OPENSSL
1739c2daa00SOllivier Robert long	d0, d1, d2, d3;		/* callback counters */
1749c2daa00SOllivier Robert #endif /* OPENSSL */
1759c2daa00SOllivier Robert 
1769c2daa00SOllivier Robert #ifdef SYS_WINNT
1779c2daa00SOllivier Robert BOOL init_randfile();
1789c2daa00SOllivier Robert 
1799c2daa00SOllivier Robert /*
1809c2daa00SOllivier Robert  * Don't try to follow symbolic links
1819c2daa00SOllivier Robert  */
1829c2daa00SOllivier Robert int
1839c2daa00SOllivier Robert readlink(char * link, char * file, int len) {
1849c2daa00SOllivier Robert 	return (-1);
1859c2daa00SOllivier Robert }
1869c2daa00SOllivier Robert /*
1879c2daa00SOllivier Robert  * Don't try to create a symbolic link for now.
1889c2daa00SOllivier Robert  * Just move the file to the name you need.
1899c2daa00SOllivier Robert  */
1909c2daa00SOllivier Robert int
1919c2daa00SOllivier Robert symlink(char *filename, char *linkname) {
1929c2daa00SOllivier Robert 	DeleteFile(linkname);
1939c2daa00SOllivier Robert 	MoveFile(filename, linkname);
1949c2daa00SOllivier Robert 	return 0;
1959c2daa00SOllivier Robert }
1969c2daa00SOllivier Robert void
1979c2daa00SOllivier Robert InitWin32Sockets() {
1989c2daa00SOllivier Robert 	WORD wVersionRequested;
1999c2daa00SOllivier Robert 	WSADATA wsaData;
2009c2daa00SOllivier Robert 	wVersionRequested = MAKEWORD(2,0);
2019c2daa00SOllivier Robert 	if (WSAStartup(wVersionRequested, &wsaData))
2029c2daa00SOllivier Robert 	{
2039c2daa00SOllivier Robert 		fprintf(stderr, "No useable winsock.dll");
2049c2daa00SOllivier Robert 		exit(1);
2059c2daa00SOllivier Robert 	}
2069c2daa00SOllivier Robert }
2079c2daa00SOllivier Robert #endif /* SYS_WINNT */
2089c2daa00SOllivier Robert 
2099c2daa00SOllivier Robert /*
2109c2daa00SOllivier Robert  * Main program
2119c2daa00SOllivier Robert  */
2129c2daa00SOllivier Robert int
2139c2daa00SOllivier Robert main(
2149c2daa00SOllivier Robert 	int	argc,		/* command line options */
2159c2daa00SOllivier Robert 	char	**argv
2169c2daa00SOllivier Robert 	)
2179c2daa00SOllivier Robert {
2189c2daa00SOllivier Robert 	struct timeval tv;	/* initialization vector */
2199c2daa00SOllivier Robert #ifdef OPENSSL
2209c2daa00SOllivier Robert 	X509	*cert = NULL;	/* X509 certificate */
2219c2daa00SOllivier Robert 	EVP_PKEY *pkey_host = NULL; /* host key */
2229c2daa00SOllivier Robert 	EVP_PKEY *pkey_sign = NULL; /* sign key */
2239c2daa00SOllivier Robert 	EVP_PKEY *pkey_iff = NULL; /* IFF parameters */
2249c2daa00SOllivier Robert 	EVP_PKEY *pkey_gq = NULL; /* GQ parameters */
2259c2daa00SOllivier Robert 	EVP_PKEY *pkey_mv = NULL; /* MV parameters */
2265e91a9b7SOllivier Robert #endif
2279c2daa00SOllivier Robert 	int	md5key = 0;	/* generate MD5 keys */
2285e91a9b7SOllivier Robert #ifdef OPENSSL
2299c2daa00SOllivier Robert 	int	hostkey = 0;	/* generate RSA keys */
2309c2daa00SOllivier Robert 	int	iffkey = 0;	/* generate IFF parameters */
2319c2daa00SOllivier Robert 	int	gqpar = 0;	/* generate GQ parameters */
2329c2daa00SOllivier Robert 	int	gqkey = 0;	/* update GQ keys */
2339c2daa00SOllivier Robert 	int	mvpar = 0;	/* generate MV parameters */
2349c2daa00SOllivier Robert 	int	mvkey = 0;	/* update MV keys */
2359c2daa00SOllivier Robert 	char	*sign = NULL;	/* sign key */
2369c2daa00SOllivier Robert 	EVP_PKEY *pkey = NULL;	/* temp key */
2379c2daa00SOllivier Robert 	const EVP_MD *ectx;	/* EVP digest */
2389c2daa00SOllivier Robert 	char	pathbuf[MAXFILENAME + 1];
2399c2daa00SOllivier Robert 	const char *scheme = NULL; /* digest/signature scheme */
2409c2daa00SOllivier Robert 	char	*exten = NULL;	/* private extension */
2419c2daa00SOllivier Robert 	char	*grpkey = NULL;	/* identity extension */
2429c2daa00SOllivier Robert 	int	nid;		/* X509 digest/signature scheme */
2439c2daa00SOllivier Robert 	FILE	*fstr = NULL;	/* file handle */
2449c2daa00SOllivier Robert 	int	iffsw = 0;	/* IFF key switch */
2459c2daa00SOllivier Robert #endif /* OPENSSL */
2465e91a9b7SOllivier Robert 	char	hostbuf[MAXHOSTNAME + 1];
2479c2daa00SOllivier Robert 	u_int	temp;
2489c2daa00SOllivier Robert 
2499c2daa00SOllivier Robert #ifdef SYS_WINNT
2509c2daa00SOllivier Robert 	/* Initialize before OpenSSL checks */
2519c2daa00SOllivier Robert 	InitWin32Sockets();
2529c2daa00SOllivier Robert 	if(!init_randfile())
2539c2daa00SOllivier Robert 		fprintf(stderr, "Unable to initialize .rnd file\n");
2549c2daa00SOllivier Robert #endif
2559c2daa00SOllivier Robert 
2569c2daa00SOllivier Robert #ifdef OPENSSL
2579c2daa00SOllivier Robert 	if (SSLeay() != OPENSSL_VERSION_NUMBER) {
2589c2daa00SOllivier Robert 		fprintf(stderr,
2599c2daa00SOllivier Robert 		    "OpenSSL version mismatch. Built against %lx, you have %lx\n",
2609c2daa00SOllivier Robert 		    OPENSSL_VERSION_NUMBER, SSLeay());
2619c2daa00SOllivier Robert 		return (-1);
2629c2daa00SOllivier Robert 
2639c2daa00SOllivier Robert 	} else {
2649c2daa00SOllivier Robert 		fprintf(stderr,
2659c2daa00SOllivier Robert 		    "Using OpenSSL version %lx\n", SSLeay());
2669c2daa00SOllivier Robert 	}
2679c2daa00SOllivier Robert #endif /* OPENSSL */
2689c2daa00SOllivier Robert 
2699c2daa00SOllivier Robert 	/*
2709c2daa00SOllivier Robert 	 * Process options, initialize host name and timestamp.
2719c2daa00SOllivier Robert 	 */
2729c2daa00SOllivier Robert 	gethostname(hostbuf, MAXHOSTNAME);
2739c2daa00SOllivier Robert 	hostname = hostbuf;
2745e91a9b7SOllivier Robert #ifdef OPENSSL
2759c2daa00SOllivier Robert 	trustname = hostbuf;
2769c2daa00SOllivier Robert 	passwd1 = hostbuf;
2775e91a9b7SOllivier Robert #endif
2789c2daa00SOllivier Robert #ifndef SYS_WINNT
2799c2daa00SOllivier Robert 	gettimeofday(&tv, 0);
2809c2daa00SOllivier Robert #else
2819c2daa00SOllivier Robert 	gettimeofday(&tv);
2829c2daa00SOllivier Robert #endif
2839c2daa00SOllivier Robert 	epoch = tv.tv_sec;
2849c2daa00SOllivier Robert 	rval = 0;
2859c2daa00SOllivier Robert 	while ((temp = getopt(argc, argv,
2865e91a9b7SOllivier Robert #ifdef OPENSSL
2875e91a9b7SOllivier Robert 	    "c:deGgHIi:Mm:nPp:q:S:s:TV:v:"
2885e91a9b7SOllivier Robert #else
2895e91a9b7SOllivier Robert 	    "dM"
2905e91a9b7SOllivier Robert #endif
2915e91a9b7SOllivier Robert 	    )) != -1) {
2929c2daa00SOllivier Robert 		switch(temp) {
2939c2daa00SOllivier Robert 
2945e91a9b7SOllivier Robert #ifdef OPENSSL
2959c2daa00SOllivier Robert 		/*
2969c2daa00SOllivier Robert 		 * -c select public certificate type
2979c2daa00SOllivier Robert 		 */
2989c2daa00SOllivier Robert 		case 'c':
2999c2daa00SOllivier Robert 			scheme = optarg;
3009c2daa00SOllivier Robert 			continue;
3015e91a9b7SOllivier Robert #endif
3029c2daa00SOllivier Robert 
3039c2daa00SOllivier Robert 		/*
3049c2daa00SOllivier Robert 		 * -d debug
3059c2daa00SOllivier Robert 		 */
3069c2daa00SOllivier Robert 		case 'd':
3079c2daa00SOllivier Robert 			debug++;
3089c2daa00SOllivier Robert 			continue;
3099c2daa00SOllivier Robert 
3105e91a9b7SOllivier Robert #ifdef OPENSSL
3119c2daa00SOllivier Robert 		/*
3129c2daa00SOllivier Robert 		 * -e write identity keys
3139c2daa00SOllivier Robert 		 */
3149c2daa00SOllivier Robert 		case 'e':
3159c2daa00SOllivier Robert 			iffsw++;
3169c2daa00SOllivier Robert 			continue;
3175e91a9b7SOllivier Robert #endif
3189c2daa00SOllivier Robert 
3195e91a9b7SOllivier Robert #ifdef OPENSSL
3209c2daa00SOllivier Robert 		/*
3219c2daa00SOllivier Robert 		 * -G generate GQ parameters and keys
3229c2daa00SOllivier Robert 		 */
3239c2daa00SOllivier Robert 		case 'G':
3249c2daa00SOllivier Robert 			gqpar++;
3259c2daa00SOllivier Robert 			continue;
3265e91a9b7SOllivier Robert #endif
3279c2daa00SOllivier Robert 
3285e91a9b7SOllivier Robert #ifdef OPENSSL
3299c2daa00SOllivier Robert 		/*
3309c2daa00SOllivier Robert 		 * -g update GQ keys
3319c2daa00SOllivier Robert 		 */
3329c2daa00SOllivier Robert 		case 'g':
3339c2daa00SOllivier Robert 			gqkey++;
3349c2daa00SOllivier Robert 			continue;
3355e91a9b7SOllivier Robert #endif
3369c2daa00SOllivier Robert 
3375e91a9b7SOllivier Robert #ifdef OPENSSL
3389c2daa00SOllivier Robert 		/*
3399c2daa00SOllivier Robert 		 * -H generate host key (RSA)
3409c2daa00SOllivier Robert 		 */
3419c2daa00SOllivier Robert 		case 'H':
3429c2daa00SOllivier Robert 			hostkey++;
3439c2daa00SOllivier Robert 			continue;
3445e91a9b7SOllivier Robert #endif
3459c2daa00SOllivier Robert 
3465e91a9b7SOllivier Robert #ifdef OPENSSL
3479c2daa00SOllivier Robert 		/*
3489c2daa00SOllivier Robert 		 * -I generate IFF parameters
3499c2daa00SOllivier Robert 		 */
3509c2daa00SOllivier Robert 		case 'I':
3519c2daa00SOllivier Robert 			iffkey++;
3529c2daa00SOllivier Robert 			continue;
3535e91a9b7SOllivier Robert #endif
3549c2daa00SOllivier Robert 
3555e91a9b7SOllivier Robert #ifdef OPENSSL
3569c2daa00SOllivier Robert 		/*
3579c2daa00SOllivier Robert 		 * -i set issuer name
3589c2daa00SOllivier Robert 		 */
3599c2daa00SOllivier Robert 		case 'i':
3609c2daa00SOllivier Robert 			trustname = optarg;
3619c2daa00SOllivier Robert 			continue;
3625e91a9b7SOllivier Robert #endif
3639c2daa00SOllivier Robert 
3649c2daa00SOllivier Robert 		/*
3659c2daa00SOllivier Robert 		 * -M generate MD5 keys
3669c2daa00SOllivier Robert 		 */
3679c2daa00SOllivier Robert 		case 'M':
3689c2daa00SOllivier Robert 			md5key++;
3699c2daa00SOllivier Robert 			continue;
3709c2daa00SOllivier Robert 
3715e91a9b7SOllivier Robert #ifdef OPENSSL
3729c2daa00SOllivier Robert 		/*
3739c2daa00SOllivier Robert 		 * -m select modulus (256-2048)
3749c2daa00SOllivier Robert 		 */
3759c2daa00SOllivier Robert 		case 'm':
3769c2daa00SOllivier Robert 			if (sscanf(optarg, "%d", &modulus) != 1)
3779c2daa00SOllivier Robert 				fprintf(stderr,
3789c2daa00SOllivier Robert 				    "invalid option -m %s\n", optarg);
3799c2daa00SOllivier Robert 			continue;
3805e91a9b7SOllivier Robert #endif
3819c2daa00SOllivier Robert 
3825e91a9b7SOllivier Robert #ifdef OPENSSL
3839c2daa00SOllivier Robert 		/*
3849c2daa00SOllivier Robert 		 * -P generate PC private certificate
3859c2daa00SOllivier Robert 		 */
3869c2daa00SOllivier Robert 		case 'P':
3879c2daa00SOllivier Robert 			exten = EXT_KEY_PRIVATE;
3889c2daa00SOllivier Robert 			continue;
3895e91a9b7SOllivier Robert #endif
3909c2daa00SOllivier Robert 
3915e91a9b7SOllivier Robert #ifdef OPENSSL
3929c2daa00SOllivier Robert 		/*
3939c2daa00SOllivier Robert 		 * -p output private key password
3949c2daa00SOllivier Robert 		 */
3959c2daa00SOllivier Robert 		case 'p':
3969c2daa00SOllivier Robert 			passwd2 = optarg;
3979c2daa00SOllivier Robert 			continue;
3985e91a9b7SOllivier Robert #endif
3999c2daa00SOllivier Robert 
4005e91a9b7SOllivier Robert #ifdef OPENSSL
4019c2daa00SOllivier Robert 		/*
4029c2daa00SOllivier Robert 		 * -q input private key password
4039c2daa00SOllivier Robert 		 */
4049c2daa00SOllivier Robert 		case 'q':
4059c2daa00SOllivier Robert 			passwd1 = optarg;
4069c2daa00SOllivier Robert 			continue;
4075e91a9b7SOllivier Robert #endif
4089c2daa00SOllivier Robert 
4095e91a9b7SOllivier Robert #ifdef OPENSSL
4109c2daa00SOllivier Robert 		/*
4119c2daa00SOllivier Robert 		 * -S generate sign key (RSA or DSA)
4129c2daa00SOllivier Robert 		 */
4139c2daa00SOllivier Robert 		case 'S':
4149c2daa00SOllivier Robert 			sign = optarg;
4159c2daa00SOllivier Robert 			continue;
4165e91a9b7SOllivier Robert #endif
4179c2daa00SOllivier Robert 
4185e91a9b7SOllivier Robert #ifdef OPENSSL
4199c2daa00SOllivier Robert 		/*
4209c2daa00SOllivier Robert 		 * -s set subject name
4219c2daa00SOllivier Robert 		 */
4229c2daa00SOllivier Robert 		case 's':
4239c2daa00SOllivier Robert 			hostname = optarg;
4249c2daa00SOllivier Robert 			continue;
4255e91a9b7SOllivier Robert #endif
4269c2daa00SOllivier Robert 
4275e91a9b7SOllivier Robert #ifdef OPENSSL
4289c2daa00SOllivier Robert 		/*
4299c2daa00SOllivier Robert 		 * -T trusted certificate (TC scheme)
4309c2daa00SOllivier Robert 		 */
4319c2daa00SOllivier Robert 		case 'T':
4329c2daa00SOllivier Robert 			exten = EXT_KEY_TRUST;
4339c2daa00SOllivier Robert 			continue;
4345e91a9b7SOllivier Robert #endif
4359c2daa00SOllivier Robert 
4365e91a9b7SOllivier Robert #ifdef OPENSSL
4379c2daa00SOllivier Robert 		/*
4389c2daa00SOllivier Robert 		 * -V <keys> generate MV parameters
4399c2daa00SOllivier Robert 		 */
4409c2daa00SOllivier Robert 		case 'V':
4419c2daa00SOllivier Robert 			mvpar++;
4429c2daa00SOllivier Robert 			if (sscanf(optarg, "%d", &nkeys) != 1)
4439c2daa00SOllivier Robert 				fprintf(stderr,
4449c2daa00SOllivier Robert 				    "invalid option -V %s\n", optarg);
4459c2daa00SOllivier Robert 			continue;
4465e91a9b7SOllivier Robert #endif
4479c2daa00SOllivier Robert 
4485e91a9b7SOllivier Robert #ifdef OPENSSL
4499c2daa00SOllivier Robert 		/*
4509c2daa00SOllivier Robert 		 * -v <key> update MV keys
4519c2daa00SOllivier Robert 		 */
4529c2daa00SOllivier Robert 		case 'v':
4539c2daa00SOllivier Robert 			mvkey++;
4549c2daa00SOllivier Robert 			if (sscanf(optarg, "%d", &nkeys) != 1)
4559c2daa00SOllivier Robert 				fprintf(stderr,
4569c2daa00SOllivier Robert 				    "invalid option -v %s\n", optarg);
4579c2daa00SOllivier Robert 			continue;
4585e91a9b7SOllivier Robert #endif
4599c2daa00SOllivier Robert 
4609c2daa00SOllivier Robert 		/*
4619c2daa00SOllivier Robert 		 * None of the above.
4629c2daa00SOllivier Robert 		 */
4639c2daa00SOllivier Robert 		default:
4649c2daa00SOllivier Robert 			fprintf(stderr, "Option ignored\n");
4659c2daa00SOllivier Robert 			continue;
4669c2daa00SOllivier Robert 		}
4679c2daa00SOllivier Robert 	}
4689c2daa00SOllivier Robert 
4699c2daa00SOllivier Robert 	if (passwd1 != NULL && passwd2 == NULL)
4709c2daa00SOllivier Robert 		passwd2 = passwd1;
4719c2daa00SOllivier Robert #ifdef OPENSSL
4729c2daa00SOllivier Robert 	/*
4739c2daa00SOllivier Robert 	 * Seed random number generator and grow weeds.
4749c2daa00SOllivier Robert 	 */
4759c2daa00SOllivier Robert 	ERR_load_crypto_strings();
4769c2daa00SOllivier Robert 	OpenSSL_add_all_algorithms();
4779c2daa00SOllivier Robert 	if (RAND_file_name(pathbuf, MAXFILENAME) == NULL) {
4789c2daa00SOllivier Robert 		fprintf(stderr, "RAND_file_name %s\n",
4799c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
4809c2daa00SOllivier Robert 		return (-1);
4819c2daa00SOllivier Robert 	}
4829c2daa00SOllivier Robert 	temp = RAND_load_file(pathbuf, -1);
4839c2daa00SOllivier Robert 	if (temp == 0) {
4849c2daa00SOllivier Robert 		fprintf(stderr,
4859c2daa00SOllivier Robert 		    "RAND_load_file %s not found or empty\n", pathbuf);
4869c2daa00SOllivier Robert 		return (-1);
4879c2daa00SOllivier Robert 	}
4889c2daa00SOllivier Robert 	fprintf(stderr,
4899c2daa00SOllivier Robert 	    "Random seed file %s %u bytes\n", pathbuf, temp);
4909c2daa00SOllivier Robert 	RAND_add(&epoch, sizeof(epoch), 4.0);
4915e91a9b7SOllivier Robert #endif
4929c2daa00SOllivier Robert 
4939c2daa00SOllivier Robert 	/*
4949c2daa00SOllivier Robert 	 * Generate new parameters and keys as requested. These replace
4959c2daa00SOllivier Robert 	 * any values already generated.
4969c2daa00SOllivier Robert 	 */
4979c2daa00SOllivier Robert 	if (md5key)
4989c2daa00SOllivier Robert 		gen_md5("MD5");
4995e91a9b7SOllivier Robert #ifdef OPENSSL
5009c2daa00SOllivier Robert 	if (hostkey)
5019c2daa00SOllivier Robert 		pkey_host = genkey("RSA", "host");
5029c2daa00SOllivier Robert 	if (sign != NULL)
5039c2daa00SOllivier Robert 		pkey_sign = genkey(sign, "sign");
5049c2daa00SOllivier Robert 	if (iffkey)
5059c2daa00SOllivier Robert 		pkey_iff = gen_iff("iff");
5069c2daa00SOllivier Robert 	if (gqpar)
5079c2daa00SOllivier Robert 		pkey_gq = gen_gqpar("gq");
5089c2daa00SOllivier Robert 	if (mvpar)
5099c2daa00SOllivier Robert 		pkey_mv = gen_mv("mv");
5109c2daa00SOllivier Robert 
5119c2daa00SOllivier Robert 	/*
5129c2daa00SOllivier Robert 	 * If there is no new host key, look for an existing one. If not
5139c2daa00SOllivier Robert 	 * found, create it.
5149c2daa00SOllivier Robert 	 */
5159c2daa00SOllivier Robert 	while (pkey_host == NULL && rval == 0 && !iffsw) {
5169c2daa00SOllivier Robert 		sprintf(filename, "ntpkey_host_%s", hostname);
5179c2daa00SOllivier Robert 		if ((fstr = fopen(filename, "r")) != NULL) {
5189c2daa00SOllivier Robert 			pkey_host = PEM_read_PrivateKey(fstr, NULL,
5199c2daa00SOllivier Robert 			    NULL, passwd1);
5209c2daa00SOllivier Robert 			fclose(fstr);
5219c2daa00SOllivier Robert 			readlink(filename, filename,  sizeof(filename));
5229c2daa00SOllivier Robert 			if (pkey_host == NULL) {
5239c2daa00SOllivier Robert 				fprintf(stderr, "Host key\n%s\n",
5249c2daa00SOllivier Robert 				    ERR_error_string(ERR_get_error(),
5259c2daa00SOllivier Robert 				    NULL));
5269c2daa00SOllivier Robert 				rval = -1;
5279c2daa00SOllivier Robert 			} else {
5289c2daa00SOllivier Robert 				fprintf(stderr,
5299c2daa00SOllivier Robert 				    "Using host key %s\n", filename);
5309c2daa00SOllivier Robert 			}
5319c2daa00SOllivier Robert 			break;
5329c2daa00SOllivier Robert 
5339c2daa00SOllivier Robert 		} else if ((pkey_host = genkey("RSA", "host")) ==
5349c2daa00SOllivier Robert 		    NULL) {
5359c2daa00SOllivier Robert 			rval = -1;
5369c2daa00SOllivier Robert 			break;
5379c2daa00SOllivier Robert 		}
5389c2daa00SOllivier Robert 	}
5399c2daa00SOllivier Robert 
5409c2daa00SOllivier Robert 	/*
5419c2daa00SOllivier Robert 	 * If there is no new sign key, look for an existing one. If not
5429c2daa00SOllivier Robert 	 * found, use the host key instead.
5439c2daa00SOllivier Robert 	 */
5449c2daa00SOllivier Robert 	pkey = pkey_sign;
5459c2daa00SOllivier Robert 	while (pkey_sign == NULL && rval == 0 && !iffsw) {
5469c2daa00SOllivier Robert 		sprintf(filename, "ntpkey_sign_%s", hostname);
5479c2daa00SOllivier Robert 		if ((fstr = fopen(filename, "r")) != NULL) {
5489c2daa00SOllivier Robert 			pkey_sign = PEM_read_PrivateKey(fstr, NULL,
5499c2daa00SOllivier Robert 			    NULL, passwd1);
5509c2daa00SOllivier Robert 			fclose(fstr);
5519c2daa00SOllivier Robert 			readlink(filename, filename, sizeof(filename));
5529c2daa00SOllivier Robert 			if (pkey_sign == NULL) {
5539c2daa00SOllivier Robert 				fprintf(stderr, "Sign key\n%s\n",
5549c2daa00SOllivier Robert 				    ERR_error_string(ERR_get_error(),
5559c2daa00SOllivier Robert 				    NULL));
5569c2daa00SOllivier Robert 				rval = -1;
5579c2daa00SOllivier Robert 			} else {
5589c2daa00SOllivier Robert 				fprintf(stderr, "Using sign key %s\n",
5599c2daa00SOllivier Robert 				    filename);
5609c2daa00SOllivier Robert 			}
5619c2daa00SOllivier Robert 			break;
5629c2daa00SOllivier Robert 		} else {
5639c2daa00SOllivier Robert 			pkey = pkey_host;
5649c2daa00SOllivier Robert 			fprintf(stderr, "Using host key as sign key\n");
5659c2daa00SOllivier Robert 			break;
5669c2daa00SOllivier Robert 		}
5679c2daa00SOllivier Robert 	}
5689c2daa00SOllivier Robert 
5699c2daa00SOllivier Robert 	/*
5709c2daa00SOllivier Robert 	 * If there is no new IFF file, look for an existing one.
5719c2daa00SOllivier Robert 	 */
5729c2daa00SOllivier Robert 	if (pkey_iff == NULL && rval == 0) {
5739c2daa00SOllivier Robert 		sprintf(filename, "ntpkey_iff_%s", hostname);
5749c2daa00SOllivier Robert 		if ((fstr = fopen(filename, "r")) != NULL) {
5759c2daa00SOllivier Robert 			pkey_iff = PEM_read_PrivateKey(fstr, NULL,
5769c2daa00SOllivier Robert 			    NULL, passwd1);
5779c2daa00SOllivier Robert 			fclose(fstr);
5789c2daa00SOllivier Robert 			readlink(filename, filename, sizeof(filename));
5799c2daa00SOllivier Robert 			if (pkey_iff == NULL) {
5809c2daa00SOllivier Robert 				fprintf(stderr, "IFF parameters\n%s\n",
5819c2daa00SOllivier Robert 				    ERR_error_string(ERR_get_error(),
5829c2daa00SOllivier Robert 				    NULL));
5839c2daa00SOllivier Robert 				rval = -1;
5849c2daa00SOllivier Robert 			} else {
5859c2daa00SOllivier Robert 				fprintf(stderr,
5869c2daa00SOllivier Robert 				    "Using IFF parameters %s\n",
5879c2daa00SOllivier Robert 				    filename);
5889c2daa00SOllivier Robert 			}
5899c2daa00SOllivier Robert 		}
5909c2daa00SOllivier Robert 	}
5919c2daa00SOllivier Robert 
5929c2daa00SOllivier Robert 	/*
5939c2daa00SOllivier Robert 	 * If there is no new GQ file, look for an existing one.
5949c2daa00SOllivier Robert 	 */
5959c2daa00SOllivier Robert 	if (pkey_gq == NULL && rval == 0 && !iffsw) {
5969c2daa00SOllivier Robert 		sprintf(filename, "ntpkey_gq_%s", hostname);
5979c2daa00SOllivier Robert 		if ((fstr = fopen(filename, "r")) != NULL) {
5989c2daa00SOllivier Robert 			pkey_gq = PEM_read_PrivateKey(fstr, NULL, NULL,
5999c2daa00SOllivier Robert 			    passwd1);
6009c2daa00SOllivier Robert 			fclose(fstr);
6019c2daa00SOllivier Robert 			readlink(filename, filename, sizeof(filename));
6029c2daa00SOllivier Robert 			if (pkey_gq == NULL) {
6039c2daa00SOllivier Robert 				fprintf(stderr, "GQ parameters\n%s\n",
6049c2daa00SOllivier Robert 				    ERR_error_string(ERR_get_error(),
6059c2daa00SOllivier Robert 				    NULL));
6069c2daa00SOllivier Robert 				rval = -1;
6079c2daa00SOllivier Robert 			} else {
6089c2daa00SOllivier Robert 				fprintf(stderr,
6099c2daa00SOllivier Robert 				    "Using GQ parameters %s\n",
6109c2daa00SOllivier Robert 				    filename);
6119c2daa00SOllivier Robert 			}
6129c2daa00SOllivier Robert 		}
6139c2daa00SOllivier Robert 	}
6149c2daa00SOllivier Robert 
6159c2daa00SOllivier Robert 	/*
6169c2daa00SOllivier Robert 	 * If there is a GQ parameter file, create GQ private/public
6179c2daa00SOllivier Robert 	 * keys and extract the public key for the certificate.
6189c2daa00SOllivier Robert 	 */
6199c2daa00SOllivier Robert 	if (pkey_gq != NULL && rval == 0) {
6209c2daa00SOllivier Robert 		gen_gqkey("gq", pkey_gq);
6219c2daa00SOllivier Robert 		grpkey = BN_bn2hex(pkey_gq->pkey.rsa->q);
6229c2daa00SOllivier Robert 	}
6239c2daa00SOllivier Robert 
6249c2daa00SOllivier Robert 	/*
6259c2daa00SOllivier Robert 	 * Generate a X509v3 certificate.
6269c2daa00SOllivier Robert 	 */
6279c2daa00SOllivier Robert 	while (scheme == NULL && rval == 0 && !iffsw) {
6289c2daa00SOllivier Robert 		sprintf(filename, "ntpkey_cert_%s", hostname);
6299c2daa00SOllivier Robert 		if ((fstr = fopen(filename, "r")) != NULL) {
6309c2daa00SOllivier Robert 			cert = PEM_read_X509(fstr, NULL, NULL, NULL);
6319c2daa00SOllivier Robert 			fclose(fstr);
6329c2daa00SOllivier Robert 			readlink(filename, filename, sizeof(filename));
6339c2daa00SOllivier Robert 			if (cert == NULL) {
6349c2daa00SOllivier Robert 				fprintf(stderr, "Cert \n%s\n",
6359c2daa00SOllivier Robert 				    ERR_error_string(ERR_get_error(),
6369c2daa00SOllivier Robert 				    NULL));
6379c2daa00SOllivier Robert 				rval = -1;
6389c2daa00SOllivier Robert 			} else {
6399c2daa00SOllivier Robert 				nid = OBJ_obj2nid(
6409c2daa00SOllivier Robert 				 cert->cert_info->signature->algorithm);
6419c2daa00SOllivier Robert 				scheme = OBJ_nid2sn(nid);
6429c2daa00SOllivier Robert 				fprintf(stderr,
6439c2daa00SOllivier Robert 				    "Using scheme %s from %s\n", scheme,
6449c2daa00SOllivier Robert 				     filename);
6459c2daa00SOllivier Robert 				break;
6469c2daa00SOllivier Robert 			}
6479c2daa00SOllivier Robert 		}
6489c2daa00SOllivier Robert 		scheme = "RSA-MD5";
6499c2daa00SOllivier Robert 	}
6509c2daa00SOllivier Robert 	if (pkey != NULL && rval == 0 && !iffsw) {
6519c2daa00SOllivier Robert 		ectx = EVP_get_digestbyname(scheme);
6529c2daa00SOllivier Robert 		if (ectx == NULL) {
6539c2daa00SOllivier Robert 			fprintf(stderr,
6549c2daa00SOllivier Robert 			    "Invalid digest/signature combination %s\n",
6559c2daa00SOllivier Robert 			    scheme);
6569c2daa00SOllivier Robert 			rval = -1;
6579c2daa00SOllivier Robert 		} else {
6589c2daa00SOllivier Robert 			x509(pkey, ectx, grpkey, exten);
6599c2daa00SOllivier Robert 		}
6609c2daa00SOllivier Robert 	}
6619c2daa00SOllivier Robert 
6629c2daa00SOllivier Robert 	/*
6639c2daa00SOllivier Robert 	 * Write the IFF client parameters and keys as a DSA private key
6649c2daa00SOllivier Robert 	 * encoded in PEM. Note the private key is obscured.
6659c2daa00SOllivier Robert 	 */
6669c2daa00SOllivier Robert 	if (pkey_iff != NULL && rval == 0 && iffsw) {
6679c2daa00SOllivier Robert 		DSA	*dsa;
6689c2daa00SOllivier Robert 		char	*sptr;
6699c2daa00SOllivier Robert 
6709c2daa00SOllivier Robert 		sptr = strrchr(filename, '.');
6719c2daa00SOllivier Robert 		sprintf(filename, "ntpkey_IFFkey_%s.%s", trustname,
6729c2daa00SOllivier Robert 		    ++sptr);
6739c2daa00SOllivier Robert 		fprintf(stderr, "Writing new IFF key %s\n", filename);
6749c2daa00SOllivier Robert 		fprintf(stdout, "# %s\n# %s", filename, ctime(&epoch));
6759c2daa00SOllivier Robert 		dsa = pkey_iff->pkey.dsa;
6769c2daa00SOllivier Robert 		BN_copy(dsa->priv_key, BN_value_one());
6779c2daa00SOllivier Robert 		pkey = EVP_PKEY_new();
6789c2daa00SOllivier Robert 		EVP_PKEY_assign_DSA(pkey, dsa);
6799c2daa00SOllivier Robert 		PEM_write_PrivateKey(stdout, pkey, passwd2 ?
6809c2daa00SOllivier Robert 		    EVP_des_cbc() : NULL, NULL, 0, NULL, passwd2);
6819c2daa00SOllivier Robert 		fclose(stdout);
6829c2daa00SOllivier Robert 		if (debug)
6839c2daa00SOllivier Robert 			DSA_print_fp(stdout, dsa, 0);
6849c2daa00SOllivier Robert 	}
6859c2daa00SOllivier Robert 
6869c2daa00SOllivier Robert 	/*
6879c2daa00SOllivier Robert 	 * Return the marbles.
6889c2daa00SOllivier Robert 	 */
6899c2daa00SOllivier Robert 	if (grpkey != NULL)
6909c2daa00SOllivier Robert 		OPENSSL_free(grpkey);
6919c2daa00SOllivier Robert 	if (pkey_host != NULL)
6929c2daa00SOllivier Robert 		EVP_PKEY_free(pkey_host);
6939c2daa00SOllivier Robert 	if (pkey_sign != NULL)
6949c2daa00SOllivier Robert 		EVP_PKEY_free(pkey_sign);
6959c2daa00SOllivier Robert 	if (pkey_iff != NULL)
6969c2daa00SOllivier Robert 		EVP_PKEY_free(pkey_iff);
6979c2daa00SOllivier Robert 	if (pkey_gq != NULL)
6989c2daa00SOllivier Robert 		EVP_PKEY_free(pkey_gq);
6999c2daa00SOllivier Robert 	if (pkey_mv != NULL)
7009c2daa00SOllivier Robert 		EVP_PKEY_free(pkey_mv);
7019c2daa00SOllivier Robert #endif /* OPENSSL */
7029c2daa00SOllivier Robert 	return (rval);
7039c2daa00SOllivier Robert }
7049c2daa00SOllivier Robert 
7059c2daa00SOllivier Robert 
7069c2daa00SOllivier Robert #if 0
7079c2daa00SOllivier Robert /*
7089c2daa00SOllivier Robert  * Generate random MD5 key with password.
7099c2daa00SOllivier Robert  */
7109c2daa00SOllivier Robert int
7119c2daa00SOllivier Robert gen_md5(
7129c2daa00SOllivier Robert 	char	*id		/* file name id */
7139c2daa00SOllivier Robert 	)
7149c2daa00SOllivier Robert {
7159c2daa00SOllivier Robert 	BIGNUM	*key;
7169c2daa00SOllivier Robert 	BIGNUM	*keyid;
7179c2daa00SOllivier Robert 	FILE	*str;
7189c2daa00SOllivier Robert 	u_char	bin[16];
7199c2daa00SOllivier Robert 
7209c2daa00SOllivier Robert 	fprintf(stderr, "Generating MD5 keys...\n");
7219c2daa00SOllivier Robert 	str = fheader("MD5key", hostname);
7229c2daa00SOllivier Robert 	keyid = BN_new(); key = BN_new();
7239c2daa00SOllivier Robert 	BN_rand(keyid, 16, -1, 0);
7249c2daa00SOllivier Robert 	BN_rand(key, 128, -1, 0);
7259c2daa00SOllivier Robert 	BN_bn2bin(key, bin);
7269c2daa00SOllivier Robert 	PEM_write_fp(str, MD5, NULL, bin);
7279c2daa00SOllivier Robert 	fclose(str);
7289c2daa00SOllivier Robert 	fslink(id, hostname);
7299c2daa00SOllivier Robert 	return (1);
7309c2daa00SOllivier Robert }
7319c2daa00SOllivier Robert 
7329c2daa00SOllivier Robert 
7339c2daa00SOllivier Robert #else
7349c2daa00SOllivier Robert /*
7359c2daa00SOllivier Robert  * Generate semi-random MD5 keys compatible with NTPv3 and NTPv4
7369c2daa00SOllivier Robert  */
7379c2daa00SOllivier Robert int
7389c2daa00SOllivier Robert gen_md5(
7399c2daa00SOllivier Robert 	char	*id		/* file name id */
7409c2daa00SOllivier Robert 	)
7419c2daa00SOllivier Robert {
7429c2daa00SOllivier Robert 	u_char	md5key[16];	/* MD5 key */
7439c2daa00SOllivier Robert 	FILE	*str;
7449c2daa00SOllivier Robert 	u_int	temp = 0;	/* Initialize to prevent warnings during compile */
7459c2daa00SOllivier Robert 	int	i, j;
7469c2daa00SOllivier Robert 
7479c2daa00SOllivier Robert 	fprintf(stderr, "Generating MD5 keys...\n");
7489c2daa00SOllivier Robert 	str = fheader("MD5key", hostname);
7499c2daa00SOllivier Robert 	srandom(epoch);
7509c2daa00SOllivier Robert 	for (i = 1; i <= MD5KEYS; i++) {
7519c2daa00SOllivier Robert 		for (j = 0; j < 16; j++) {
7529c2daa00SOllivier Robert 			while (1) {
7539c2daa00SOllivier Robert 				temp = random() & 0xff;
7549c2daa00SOllivier Robert 				if (temp == '#')
7559c2daa00SOllivier Robert 					continue;
7569c2daa00SOllivier Robert 				if (temp > 0x20 && temp < 0x7f)
7579c2daa00SOllivier Robert 					break;
7589c2daa00SOllivier Robert 			}
7599c2daa00SOllivier Robert 			md5key[j] = (u_char)temp;
7609c2daa00SOllivier Robert 		}
7615e91a9b7SOllivier Robert 		md5key[15] = '\0';
7629c2daa00SOllivier Robert 		fprintf(str, "%2d MD5 %16s	# MD5 key\n", i,
7639c2daa00SOllivier Robert 		    md5key);
7649c2daa00SOllivier Robert 	}
7659c2daa00SOllivier Robert 	fclose(str);
7669c2daa00SOllivier Robert 	fslink(id, hostname);
7679c2daa00SOllivier Robert 	return (1);
7689c2daa00SOllivier Robert }
7699c2daa00SOllivier Robert #endif /* OPENSSL */
7709c2daa00SOllivier Robert 
7719c2daa00SOllivier Robert 
7729c2daa00SOllivier Robert #ifdef OPENSSL
7739c2daa00SOllivier Robert /*
7749c2daa00SOllivier Robert  * Generate RSA public/private key pair
7759c2daa00SOllivier Robert  */
7769c2daa00SOllivier Robert EVP_PKEY *			/* public/private key pair */
7779c2daa00SOllivier Robert gen_rsa(
7789c2daa00SOllivier Robert 	char	*id		/* file name id */
7799c2daa00SOllivier Robert 	)
7809c2daa00SOllivier Robert {
7819c2daa00SOllivier Robert 	EVP_PKEY *pkey;		/* private key */
7829c2daa00SOllivier Robert 	RSA	*rsa;		/* RSA parameters and key pair */
7839c2daa00SOllivier Robert 	FILE	*str;
7849c2daa00SOllivier Robert 
7859c2daa00SOllivier Robert 	fprintf(stderr, "Generating RSA keys (%d bits)...\n", modulus);
7869c2daa00SOllivier Robert 	rsa = RSA_generate_key(modulus, 3, cb, "RSA");
7879c2daa00SOllivier Robert 	fprintf(stderr, "\n");
7889c2daa00SOllivier Robert 	if (rsa == NULL) {
7899c2daa00SOllivier Robert 		fprintf(stderr, "RSA generate keys fails\n%s\n",
7909c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
7919c2daa00SOllivier Robert 		rval = -1;
7929c2daa00SOllivier Robert 		return (NULL);
7939c2daa00SOllivier Robert 	}
7949c2daa00SOllivier Robert 
7959c2daa00SOllivier Robert 	/*
7969c2daa00SOllivier Robert 	 * For signature encryption it is not necessary that the RSA
7979c2daa00SOllivier Robert 	 * parameters be strictly groomed and once in a while the
7989c2daa00SOllivier Robert 	 * modulus turns out to be non-prime. Just for grins, we check
7999c2daa00SOllivier Robert 	 * the primality.
8009c2daa00SOllivier Robert 	 */
8019c2daa00SOllivier Robert 	if (!RSA_check_key(rsa)) {
8029c2daa00SOllivier Robert 		fprintf(stderr, "Invalid RSA key\n%s\n",
8039c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
8049c2daa00SOllivier Robert 		RSA_free(rsa);
8059c2daa00SOllivier Robert 		rval = -1;
8069c2daa00SOllivier Robert 		return (NULL);
8079c2daa00SOllivier Robert 	}
8089c2daa00SOllivier Robert 
8099c2daa00SOllivier Robert 	/*
8109c2daa00SOllivier Robert 	 * Write the RSA parameters and keys as a RSA private key
8119c2daa00SOllivier Robert 	 * encoded in PEM.
8129c2daa00SOllivier Robert 	 */
8139c2daa00SOllivier Robert 	str = fheader("RSAkey", hostname);
8149c2daa00SOllivier Robert 	pkey = EVP_PKEY_new();
8159c2daa00SOllivier Robert 	EVP_PKEY_assign_RSA(pkey, rsa);
8169c2daa00SOllivier Robert 	PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL,
8179c2daa00SOllivier Robert 	    NULL, 0, NULL, passwd2);
8189c2daa00SOllivier Robert 	fclose(str);
8199c2daa00SOllivier Robert 	if (debug)
8209c2daa00SOllivier Robert 		RSA_print_fp(stdout, rsa, 0);
8219c2daa00SOllivier Robert 	fslink(id, hostname);
8229c2daa00SOllivier Robert 	return (pkey);
8239c2daa00SOllivier Robert }
8249c2daa00SOllivier Robert 
8259c2daa00SOllivier Robert 
8269c2daa00SOllivier Robert /*
8279c2daa00SOllivier Robert  * Generate DSA public/private key pair
8289c2daa00SOllivier Robert  */
8299c2daa00SOllivier Robert EVP_PKEY *			/* public/private key pair */
8309c2daa00SOllivier Robert gen_dsa(
8319c2daa00SOllivier Robert 	char	*id		/* file name id */
8329c2daa00SOllivier Robert 	)
8339c2daa00SOllivier Robert {
8349c2daa00SOllivier Robert 	EVP_PKEY *pkey;		/* private key */
8359c2daa00SOllivier Robert 	DSA	*dsa;		/* DSA parameters */
8369c2daa00SOllivier Robert 	u_char	seed[20];	/* seed for parameters */
8379c2daa00SOllivier Robert 	FILE	*str;
8389c2daa00SOllivier Robert 
8399c2daa00SOllivier Robert 	/*
8409c2daa00SOllivier Robert 	 * Generate DSA parameters.
8419c2daa00SOllivier Robert 	 */
8429c2daa00SOllivier Robert 	fprintf(stderr,
8439c2daa00SOllivier Robert 	    "Generating DSA parameters (%d bits)...\n", modulus);
8449c2daa00SOllivier Robert 	RAND_bytes(seed, sizeof(seed));
8459c2daa00SOllivier Robert 	dsa = DSA_generate_parameters(modulus, seed, sizeof(seed), NULL,
8469c2daa00SOllivier Robert 	    NULL, cb, "DSA");
8479c2daa00SOllivier Robert 	fprintf(stderr, "\n");
8489c2daa00SOllivier Robert 	if (dsa == NULL) {
8499c2daa00SOllivier Robert 		fprintf(stderr, "DSA generate parameters fails\n%s\n",
8509c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
8519c2daa00SOllivier Robert 		rval = -1;
8529c2daa00SOllivier Robert 		return (NULL);
8539c2daa00SOllivier Robert 	}
8549c2daa00SOllivier Robert 
8559c2daa00SOllivier Robert 	/*
8569c2daa00SOllivier Robert 	 * Generate DSA keys.
8579c2daa00SOllivier Robert 	 */
8589c2daa00SOllivier Robert 	fprintf(stderr, "Generating DSA keys (%d bits)...\n", modulus);
8599c2daa00SOllivier Robert 	if (!DSA_generate_key(dsa)) {
8609c2daa00SOllivier Robert 		fprintf(stderr, "DSA generate keys fails\n%s\n",
8619c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
8629c2daa00SOllivier Robert 		DSA_free(dsa);
8639c2daa00SOllivier Robert 		rval = -1;
8649c2daa00SOllivier Robert 		return (NULL);
8659c2daa00SOllivier Robert 	}
8669c2daa00SOllivier Robert 
8679c2daa00SOllivier Robert 	/*
8689c2daa00SOllivier Robert 	 * Write the DSA parameters and keys as a DSA private key
8699c2daa00SOllivier Robert 	 * encoded in PEM.
8709c2daa00SOllivier Robert 	 */
8719c2daa00SOllivier Robert 	str = fheader("DSAkey", hostname);
8729c2daa00SOllivier Robert 	pkey = EVP_PKEY_new();
8739c2daa00SOllivier Robert 	EVP_PKEY_assign_DSA(pkey, dsa);
8749c2daa00SOllivier Robert 	PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL,
8759c2daa00SOllivier Robert 	    NULL, 0, NULL, passwd2);
8769c2daa00SOllivier Robert 	fclose(str);
8779c2daa00SOllivier Robert 	if (debug)
8789c2daa00SOllivier Robert 		DSA_print_fp(stdout, dsa, 0);
8799c2daa00SOllivier Robert 	fslink(id, hostname);
8809c2daa00SOllivier Robert 	return (pkey);
8819c2daa00SOllivier Robert }
8829c2daa00SOllivier Robert 
8839c2daa00SOllivier Robert 
8849c2daa00SOllivier Robert /*
8859c2daa00SOllivier Robert  * Generate Schnorr (IFF) parameters and keys
8869c2daa00SOllivier Robert  *
8879c2daa00SOllivier Robert  * The Schnorr (IFF)identity scheme is intended for use when
8889c2daa00SOllivier Robert  * certificates are generated by some other trusted certificate
8899c2daa00SOllivier Robert  * authority and the parameters cannot be conveyed in the certificate
8909c2daa00SOllivier Robert  * itself. For this purpose, new generations of IFF values must be
8919c2daa00SOllivier Robert  * securely transmitted to all members of the group before use. There
8929c2daa00SOllivier Robert  * are two kinds of files: server/client files that include private and
8939c2daa00SOllivier Robert  * public parameters and client files that include only public
8949c2daa00SOllivier Robert  * parameters. The scheme is self contained and independent of new
8959c2daa00SOllivier Robert  * generations of host keys, sign keys and certificates.
8969c2daa00SOllivier Robert  *
8979c2daa00SOllivier Robert  * The IFF values hide in a DSA cuckoo structure which uses the same
8989c2daa00SOllivier Robert  * parameters. The values are used by an identity scheme based on DSA
8999c2daa00SOllivier Robert  * cryptography and described in Stimson p. 285. The p is a 512-bit
9009c2daa00SOllivier Robert  * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1
9019c2daa00SOllivier Robert  * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a
9029c2daa00SOllivier Robert  * private random group key b (0 < b < q), then computes public
9039c2daa00SOllivier Robert  * v = g^(q - a). All values except the group key are known to all group
9049c2daa00SOllivier Robert  * members; the group key is known to the group servers, but not the
9059c2daa00SOllivier Robert  * group clients. Alice challenges Bob to confirm identity using the
9069c2daa00SOllivier Robert  * protocol described below.
9079c2daa00SOllivier Robert  */
9089c2daa00SOllivier Robert EVP_PKEY *			/* DSA cuckoo nest */
9099c2daa00SOllivier Robert gen_iff(
9109c2daa00SOllivier Robert 	char	*id		/* file name id */
9119c2daa00SOllivier Robert 	)
9129c2daa00SOllivier Robert {
9139c2daa00SOllivier Robert 	EVP_PKEY *pkey;		/* private key */
9149c2daa00SOllivier Robert 	DSA	*dsa;		/* DSA parameters */
9159c2daa00SOllivier Robert 	u_char	seed[20];	/* seed for parameters */
9169c2daa00SOllivier Robert 	BN_CTX	*ctx;		/* BN working space */
9179c2daa00SOllivier Robert 	BIGNUM	*b, *r, *k, *u, *v, *w; /* BN temp */
9189c2daa00SOllivier Robert 	FILE	*str;
9199c2daa00SOllivier Robert 	u_int	temp;
9209c2daa00SOllivier Robert 
9219c2daa00SOllivier Robert 	/*
9229c2daa00SOllivier Robert 	 * Generate DSA parameters for use as IFF parameters.
9239c2daa00SOllivier Robert 	 */
9249c2daa00SOllivier Robert 	fprintf(stderr, "Generating IFF parameters (%d bits)...\n",
9259c2daa00SOllivier Robert 	    modulus);
9269c2daa00SOllivier Robert 	RAND_bytes(seed, sizeof(seed));
9279c2daa00SOllivier Robert 	dsa = DSA_generate_parameters(modulus, seed, sizeof(seed), NULL,
9289c2daa00SOllivier Robert 	    NULL, cb, "IFF");
9299c2daa00SOllivier Robert 	fprintf(stderr, "\n");
9309c2daa00SOllivier Robert 	if (dsa == NULL) {
9319c2daa00SOllivier Robert 		fprintf(stderr, "DSA generate parameters fails\n%s\n",
9329c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
9339c2daa00SOllivier Robert 		rval = -1;
9349c2daa00SOllivier Robert 		return (NULL);;
9359c2daa00SOllivier Robert 	}
9369c2daa00SOllivier Robert 
9379c2daa00SOllivier Robert 	/*
9389c2daa00SOllivier Robert 	 * Generate the private and public keys. The DSA parameters and
9399c2daa00SOllivier Robert 	 * these keys are distributed to all members of the group.
9409c2daa00SOllivier Robert 	 */
9419c2daa00SOllivier Robert 	fprintf(stderr, "Generating IFF keys (%d bits)...\n", modulus);
9429c2daa00SOllivier Robert 	b = BN_new(); r = BN_new(); k = BN_new();
9439c2daa00SOllivier Robert 	u = BN_new(); v = BN_new(); w = BN_new(); ctx = BN_CTX_new();
9449c2daa00SOllivier Robert 	BN_rand(b, BN_num_bits(dsa->q), -1, 0);	/* a */
9459c2daa00SOllivier Robert 	BN_mod(b, b, dsa->q, ctx);
9469c2daa00SOllivier Robert 	BN_sub(v, dsa->q, b);
9479c2daa00SOllivier Robert 	BN_mod_exp(v, dsa->g, v, dsa->p, ctx); /* g^(q - b) mod p */
9489c2daa00SOllivier Robert 	BN_mod_exp(u, dsa->g, b, dsa->p, ctx);	/* g^b mod p */
9499c2daa00SOllivier Robert 	BN_mod_mul(u, u, v, dsa->p, ctx);
9509c2daa00SOllivier Robert 	temp = BN_is_one(u);
9519c2daa00SOllivier Robert 	fprintf(stderr,
9529c2daa00SOllivier Robert 	    "Confirm g^(q - b) g^b = 1 mod p: %s\n", temp == 1 ?
9539c2daa00SOllivier Robert 	    "yes" : "no");
9549c2daa00SOllivier Robert 	if (!temp) {
9559c2daa00SOllivier Robert 		BN_free(b); BN_free(r); BN_free(k);
9569c2daa00SOllivier Robert 		BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx);
9579c2daa00SOllivier Robert 		rval = -1;
9589c2daa00SOllivier Robert 		return (NULL);
9599c2daa00SOllivier Robert 	}
9609c2daa00SOllivier Robert 	dsa->priv_key = BN_dup(b);		/* private key */
9619c2daa00SOllivier Robert 	dsa->pub_key = BN_dup(v);		/* public key */
9629c2daa00SOllivier Robert 
9639c2daa00SOllivier Robert 	/*
9649c2daa00SOllivier Robert 	 * Here is a trial round of the protocol. First, Alice rolls
9659c2daa00SOllivier Robert 	 * random r (0 < r < q) and sends it to Bob. She needs only
9669c2daa00SOllivier Robert 	 * modulus q.
9679c2daa00SOllivier Robert 	 */
9689c2daa00SOllivier Robert 	BN_rand(r, BN_num_bits(dsa->q), -1, 0);	/* r */
9699c2daa00SOllivier Robert 	BN_mod(r, r, dsa->q, ctx);
9709c2daa00SOllivier Robert 
9719c2daa00SOllivier Robert 	/*
9729c2daa00SOllivier Robert 	 * Bob rolls random k (0 < k < q), computes y = k + b r mod q
9739c2daa00SOllivier Robert 	 * and x = g^k mod p, then sends (y, x) to Alice. He needs
9749c2daa00SOllivier Robert 	 * moduli p, q and the group key b.
9759c2daa00SOllivier Robert 	 */
9769c2daa00SOllivier Robert 	BN_rand(k, BN_num_bits(dsa->q), -1, 0);	/* k, 0 < k < q  */
9779c2daa00SOllivier Robert 	BN_mod(k, k, dsa->q, ctx);
9789c2daa00SOllivier Robert 	BN_mod_mul(v, dsa->priv_key, r, dsa->q, ctx); /* b r mod q */
9799c2daa00SOllivier Robert 	BN_add(v, v, k);
9809c2daa00SOllivier Robert 	BN_mod(v, v, dsa->q, ctx);		/* y = k + b r mod q */
9819c2daa00SOllivier Robert 	BN_mod_exp(u, dsa->g, k, dsa->p, ctx);	/* x = g^k mod p */
9829c2daa00SOllivier Robert 
9839c2daa00SOllivier Robert 	/*
9849c2daa00SOllivier Robert 	 * Alice computes g^y v^r and verifies the result is equal to x.
9859c2daa00SOllivier Robert 	 * She needs modulus p, generator g, and the public key v, as
9869c2daa00SOllivier Robert 	 * well as her original r.
9879c2daa00SOllivier Robert 	 */
9889c2daa00SOllivier Robert 	BN_mod_exp(v, dsa->g, v, dsa->p, ctx); /* g^y mod p */
9899c2daa00SOllivier Robert 	BN_mod_exp(w, dsa->pub_key, r, dsa->p, ctx); /* v^r */
9909c2daa00SOllivier Robert 	BN_mod_mul(v, w, v, dsa->p, ctx);	/* product mod p */
9919c2daa00SOllivier Robert 	temp = BN_cmp(u, v);
9929c2daa00SOllivier Robert 	fprintf(stderr,
9939c2daa00SOllivier Robert 	    "Confirm g^k = g^(k + b r) g^(q - b) r: %s\n", temp ==
9949c2daa00SOllivier Robert 	    0 ? "yes" : "no");
9959c2daa00SOllivier Robert 	BN_free(b); BN_free(r);	BN_free(k);
9969c2daa00SOllivier Robert 	BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx);
9979c2daa00SOllivier Robert 	if (temp != 0) {
9989c2daa00SOllivier Robert 		DSA_free(dsa);
9999c2daa00SOllivier Robert 		rval = -1;
10009c2daa00SOllivier Robert 		return (NULL);
10019c2daa00SOllivier Robert 	}
10029c2daa00SOllivier Robert 
10039c2daa00SOllivier Robert 	/*
10049c2daa00SOllivier Robert 	 * Write the IFF server parameters and keys as a DSA private key
10059c2daa00SOllivier Robert 	 * encoded in PEM.
10069c2daa00SOllivier Robert 	 *
10079c2daa00SOllivier Robert 	 * p	modulus p
10089c2daa00SOllivier Robert 	 * q	modulus q
10099c2daa00SOllivier Robert 	 * g	generator g
10109c2daa00SOllivier Robert 	 * priv_key b
10119c2daa00SOllivier Robert 	 * public_key v
10129c2daa00SOllivier Robert 	 */
10139c2daa00SOllivier Robert 	str = fheader("IFFpar", trustname);
10149c2daa00SOllivier Robert 	pkey = EVP_PKEY_new();
10159c2daa00SOllivier Robert 	EVP_PKEY_assign_DSA(pkey, dsa);
10169c2daa00SOllivier Robert 	PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL,
10179c2daa00SOllivier Robert 	    NULL, 0, NULL, passwd2);
10189c2daa00SOllivier Robert 	fclose(str);
10199c2daa00SOllivier Robert 	if (debug)
10209c2daa00SOllivier Robert 		DSA_print_fp(stdout, dsa, 0);
10219c2daa00SOllivier Robert 	fslink(id, trustname);
10229c2daa00SOllivier Robert 	return (pkey);
10239c2daa00SOllivier Robert }
10249c2daa00SOllivier Robert 
10259c2daa00SOllivier Robert 
10269c2daa00SOllivier Robert /*
10279c2daa00SOllivier Robert  * Generate Guillou-Quisquater (GQ) parameters and keys
10289c2daa00SOllivier Robert  *
10299c2daa00SOllivier Robert  * The Guillou-Quisquater (GQ) identity scheme is intended for use when
10309c2daa00SOllivier Robert  * the parameters, keys and certificates are generated by this program.
10319c2daa00SOllivier Robert  * The scheme uses a certificate extension field do convey the public
10329c2daa00SOllivier Robert  * key of a particular group identified by a group key known only to
10339c2daa00SOllivier Robert  * members of the group. The scheme is self contained and independent of
10349c2daa00SOllivier Robert  * new generations of host keys and sign keys.
10359c2daa00SOllivier Robert  *
10369c2daa00SOllivier Robert  * The GQ parameters hide in a RSA cuckoo structure which uses the same
10379c2daa00SOllivier Robert  * parameters. The values are used by an identity scheme based on RSA
10389c2daa00SOllivier Robert  * cryptography and described in Stimson p. 300 (with errors). The 512-
10399c2daa00SOllivier Robert  * bit public modulus is n = p q, where p and q are secret large primes.
10409c2daa00SOllivier Robert  * The TA rolls private random group key b as RSA exponent. These values
10419c2daa00SOllivier Robert  * are known to all group members.
10429c2daa00SOllivier Robert  *
10439c2daa00SOllivier Robert  * When rolling new certificates, a member recomputes the private and
10449c2daa00SOllivier Robert  * public keys. The private key u is a random roll, while the public key
10459c2daa00SOllivier Robert  * is the inverse obscured by the group key v = (u^-1)^b. These values
10469c2daa00SOllivier Robert  * replace the private and public keys normally generated by the RSA
10479c2daa00SOllivier Robert  * scheme. Alice challenges Bob to confirm identity using the protocol
10489c2daa00SOllivier Robert  * described below.
10499c2daa00SOllivier Robert  */
10509c2daa00SOllivier Robert EVP_PKEY *			/* RSA cuckoo nest */
10519c2daa00SOllivier Robert gen_gqpar(
10529c2daa00SOllivier Robert 	char	*id		/* file name id */
10539c2daa00SOllivier Robert 	)
10549c2daa00SOllivier Robert {
10559c2daa00SOllivier Robert 	EVP_PKEY *pkey;		/* private key */
10569c2daa00SOllivier Robert 	RSA	*rsa;		/* GQ parameters */
10579c2daa00SOllivier Robert 	BN_CTX	*ctx;		/* BN working space */
10589c2daa00SOllivier Robert 	FILE	*str;
10599c2daa00SOllivier Robert 
10609c2daa00SOllivier Robert 	/*
10619c2daa00SOllivier Robert 	 * Generate RSA parameters for use as GQ parameters.
10629c2daa00SOllivier Robert 	 */
10639c2daa00SOllivier Robert 	fprintf(stderr,
10649c2daa00SOllivier Robert 	    "Generating GQ parameters (%d bits)...\n", modulus);
10659c2daa00SOllivier Robert 	rsa = RSA_generate_key(modulus, 3, cb, "GQ");
10669c2daa00SOllivier Robert 	fprintf(stderr, "\n");
10679c2daa00SOllivier Robert 	if (rsa == NULL) {
10689c2daa00SOllivier Robert 		fprintf(stderr, "RSA generate keys fails\n%s\n",
10699c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
10709c2daa00SOllivier Robert 		rval = -1;
10719c2daa00SOllivier Robert 		return (NULL);
10729c2daa00SOllivier Robert 	}
10739c2daa00SOllivier Robert 
10749c2daa00SOllivier Robert 	/*
10759c2daa00SOllivier Robert 	 * Generate the group key b, which is saved in the e member of
10769c2daa00SOllivier Robert 	 * the RSA structure. These values are distributed to all
10779c2daa00SOllivier Robert 	 * members of the group, but shielded from all other groups. We
10789c2daa00SOllivier Robert 	 * don't use all the parameters, but set the unused ones to a
10799c2daa00SOllivier Robert 	 * small number to minimize the file size.
10809c2daa00SOllivier Robert 	 */
10819c2daa00SOllivier Robert 	ctx = BN_CTX_new();
10829c2daa00SOllivier Robert 	BN_rand(rsa->e, BN_num_bits(rsa->n), -1, 0); /* b */
10839c2daa00SOllivier Robert 	BN_mod(rsa->e, rsa->e, rsa->n, ctx);
10849c2daa00SOllivier Robert 	BN_copy(rsa->d, BN_value_one());
10859c2daa00SOllivier Robert 	BN_copy(rsa->p, BN_value_one());
10869c2daa00SOllivier Robert 	BN_copy(rsa->q, BN_value_one());
10879c2daa00SOllivier Robert 	BN_copy(rsa->dmp1, BN_value_one());
10889c2daa00SOllivier Robert 	BN_copy(rsa->dmq1, BN_value_one());
10899c2daa00SOllivier Robert 	BN_copy(rsa->iqmp, BN_value_one());
10909c2daa00SOllivier Robert 
10919c2daa00SOllivier Robert 	/*
10929c2daa00SOllivier Robert 	 * Write the GQ parameters as a RSA private key encoded in PEM.
10939c2daa00SOllivier Robert 	 * The public and private keys are filled in later.
10949c2daa00SOllivier Robert 	 *
10959c2daa00SOllivier Robert 	 * n	modulus n
10969c2daa00SOllivier Robert 	 * e	group key b
10979c2daa00SOllivier Robert 	 * (remaining values are not used)
10989c2daa00SOllivier Robert 	 */
10999c2daa00SOllivier Robert 	str = fheader("GQpar", trustname);
11009c2daa00SOllivier Robert 	pkey = EVP_PKEY_new();
11019c2daa00SOllivier Robert 	EVP_PKEY_assign_RSA(pkey, rsa);
11029c2daa00SOllivier Robert 	PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL,
11039c2daa00SOllivier Robert 	    NULL, 0, NULL, passwd2);
11049c2daa00SOllivier Robert 	fclose(str);
11059c2daa00SOllivier Robert 	if (debug)
11069c2daa00SOllivier Robert 		RSA_print_fp(stdout, rsa, 0);
11079c2daa00SOllivier Robert 	fslink(id, trustname);
11089c2daa00SOllivier Robert 	return (pkey);
11099c2daa00SOllivier Robert }
11109c2daa00SOllivier Robert 
11119c2daa00SOllivier Robert 
11129c2daa00SOllivier Robert /*
11139c2daa00SOllivier Robert  * Update Guillou-Quisquater (GQ) parameters
11149c2daa00SOllivier Robert  */
11159c2daa00SOllivier Robert EVP_PKEY *			/* RSA cuckoo nest */
11169c2daa00SOllivier Robert gen_gqkey(
11179c2daa00SOllivier Robert 	char	*id,		/* file name id */
11189c2daa00SOllivier Robert 	EVP_PKEY *gqpar		/* GQ parameters */
11199c2daa00SOllivier Robert 	)
11209c2daa00SOllivier Robert {
11219c2daa00SOllivier Robert 	EVP_PKEY *pkey;		/* private key */
11229c2daa00SOllivier Robert 	RSA	*rsa;		/* RSA parameters */
11239c2daa00SOllivier Robert 	BN_CTX	*ctx;		/* BN working space */
11249c2daa00SOllivier Robert 	BIGNUM	*u, *v, *g, *k, *r, *y; /* BN temps */
11259c2daa00SOllivier Robert 	FILE	*str;
11269c2daa00SOllivier Robert 	u_int	temp;
11279c2daa00SOllivier Robert 
11289c2daa00SOllivier Robert 	/*
11299c2daa00SOllivier Robert 	 * Generate GQ keys. Note that the group key b is the e member
11309c2daa00SOllivier Robert 	 * of
11319c2daa00SOllivier Robert 	 * the GQ parameters.
11329c2daa00SOllivier Robert 	 */
11339c2daa00SOllivier Robert 	fprintf(stderr, "Updating GQ keys (%d bits)...\n", modulus);
11349c2daa00SOllivier Robert 	ctx = BN_CTX_new(); u = BN_new(); v = BN_new();
11359c2daa00SOllivier Robert 	g = BN_new(); k = BN_new(); r = BN_new(); y = BN_new();
11369c2daa00SOllivier Robert 
11379c2daa00SOllivier Robert 	/*
11389c2daa00SOllivier Robert 	 * When generating his certificate, Bob rolls random private key
11399c2daa00SOllivier Robert 	 * u.
11409c2daa00SOllivier Robert 	 */
11419c2daa00SOllivier Robert 	rsa = gqpar->pkey.rsa;
11429c2daa00SOllivier Robert 	BN_rand(u, BN_num_bits(rsa->n), -1, 0); /* u */
11439c2daa00SOllivier Robert 	BN_mod(u, u, rsa->n, ctx);
11449c2daa00SOllivier Robert 	BN_mod_inverse(v, u, rsa->n, ctx);	/* u^-1 mod n */
11459c2daa00SOllivier Robert 	BN_mod_mul(k, v, u, rsa->n, ctx);
11469c2daa00SOllivier Robert 
11479c2daa00SOllivier Robert 	/*
11489c2daa00SOllivier Robert 	 * Bob computes public key v = (u^-1)^b, which is saved in an
11499c2daa00SOllivier Robert 	 * extension field on his certificate. We check that u^b v =
11509c2daa00SOllivier Robert 	 * 1 mod n.
11519c2daa00SOllivier Robert 	 */
11529c2daa00SOllivier Robert 	BN_mod_exp(v, v, rsa->e, rsa->n, ctx);
11539c2daa00SOllivier Robert 	BN_mod_exp(g, u, rsa->e, rsa->n, ctx); /* u^b */
11549c2daa00SOllivier Robert 	BN_mod_mul(g, g, v, rsa->n, ctx); /* u^b (u^-1)^b */
11559c2daa00SOllivier Robert 	temp = BN_is_one(g);
11569c2daa00SOllivier Robert 	fprintf(stderr,
11579c2daa00SOllivier Robert 	    "Confirm u^b (u^-1)^b = 1 mod n: %s\n", temp ? "yes" :
11589c2daa00SOllivier Robert 	    "no");
11599c2daa00SOllivier Robert 	if (!temp) {
11609c2daa00SOllivier Robert 		BN_free(u); BN_free(v);
11619c2daa00SOllivier Robert 		BN_free(g); BN_free(k); BN_free(r); BN_free(y);
11629c2daa00SOllivier Robert 		BN_CTX_free(ctx);
11639c2daa00SOllivier Robert 		RSA_free(rsa);
11649c2daa00SOllivier Robert 		rval = -1;
11659c2daa00SOllivier Robert 		return (NULL);
11669c2daa00SOllivier Robert 	}
11679c2daa00SOllivier Robert 	BN_copy(rsa->p, u);			/* private key */
11689c2daa00SOllivier Robert 	BN_copy(rsa->q, v);			/* public key */
11699c2daa00SOllivier Robert 
11709c2daa00SOllivier Robert 	/*
11719c2daa00SOllivier Robert 	 * Here is a trial run of the protocol. First, Alice rolls
11729c2daa00SOllivier Robert 	 * random r (0 < r < n) and sends it to Bob. She needs only
11739c2daa00SOllivier Robert 	 * modulus n from the parameters.
11749c2daa00SOllivier Robert 	 */
11759c2daa00SOllivier Robert 	BN_rand(r, BN_num_bits(rsa->n), -1, 0);	/* r */
11769c2daa00SOllivier Robert 	BN_mod(r, r, rsa->n, ctx);
11779c2daa00SOllivier Robert 
11789c2daa00SOllivier Robert 	/*
11799c2daa00SOllivier Robert 	 * Bob rolls random k (0 < k < n), computes y = k u^r mod n and
11809c2daa00SOllivier Robert 	 * g = k^b mod n, then sends (y, g) to Alice. He needs modulus n
11819c2daa00SOllivier Robert 	 * from the parameters and his private key u.
11829c2daa00SOllivier Robert 	 */
11839c2daa00SOllivier Robert 	BN_rand(k, BN_num_bits(rsa->n), -1, 0);	/* k */
11849c2daa00SOllivier Robert 	BN_mod(k, k, rsa->n, ctx);
11859c2daa00SOllivier Robert 	BN_mod_exp(y, rsa->p, r, rsa->n, ctx);	/* u^r mod n */
11869c2daa00SOllivier Robert 	BN_mod_mul(y, k, y, rsa->n, ctx);	/* y = k u^r mod n */
11879c2daa00SOllivier Robert 	BN_mod_exp(g, k, rsa->e, rsa->n, ctx); /* g = k^b mod n */
11889c2daa00SOllivier Robert 
11899c2daa00SOllivier Robert 	/*
11909c2daa00SOllivier Robert 	 * Alice computes v^r y^b mod n and verifies the result is equal
11919c2daa00SOllivier Robert 	 * to g. She needs modulus n, generator g and group key b from
11929c2daa00SOllivier Robert 	 * the parameters and Bob's public key v = (u^-1)^b from his
11939c2daa00SOllivier Robert 	 * certificate.
11949c2daa00SOllivier Robert 	 */
11959c2daa00SOllivier Robert 	BN_mod_exp(v, rsa->q, r, rsa->n, ctx);	/* v^r mod n */
11969c2daa00SOllivier Robert 	BN_mod_exp(y, y, rsa->e, rsa->n, ctx); /* y^b mod n */
11979c2daa00SOllivier Robert 	BN_mod_mul(y, v, y, rsa->n, ctx);	/* v^r y^b mod n */
11989c2daa00SOllivier Robert 	temp = BN_cmp(y, g);
11999c2daa00SOllivier Robert 	fprintf(stderr, "Confirm g^k = v^r y^b mod n: %s\n", temp == 0 ?
12009c2daa00SOllivier Robert 	    "yes" : "no");
12019c2daa00SOllivier Robert 	BN_CTX_free(ctx); BN_free(u); BN_free(v);
12029c2daa00SOllivier Robert 	BN_free(g); BN_free(k); BN_free(r); BN_free(y);
12039c2daa00SOllivier Robert 	if (temp != 0) {
12049c2daa00SOllivier Robert 		RSA_free(rsa);
12059c2daa00SOllivier Robert 		rval = -1;
12069c2daa00SOllivier Robert 		return (NULL);
12079c2daa00SOllivier Robert 	}
12089c2daa00SOllivier Robert 
12099c2daa00SOllivier Robert 	/*
12109c2daa00SOllivier Robert 	 * Write the GQ parameters and keys as a RSA private key encoded
12119c2daa00SOllivier Robert 	 * in PEM.
12129c2daa00SOllivier Robert 	 *
12139c2daa00SOllivier Robert 	 * n	modulus n
12149c2daa00SOllivier Robert 	 * e	group key b
12159c2daa00SOllivier Robert 	 * p	private key u
12169c2daa00SOllivier Robert 	 * q	public key (u^-1)^b
12179c2daa00SOllivier Robert 	 * (remaining values are not used)
12189c2daa00SOllivier Robert 	 */
12199c2daa00SOllivier Robert 	str = fheader("GQpar", trustname);
12209c2daa00SOllivier Robert 	pkey = EVP_PKEY_new();
12219c2daa00SOllivier Robert 	EVP_PKEY_assign_RSA(pkey, rsa);
12229c2daa00SOllivier Robert 	PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL,
12239c2daa00SOllivier Robert 	    NULL, 0, NULL, passwd2);
12249c2daa00SOllivier Robert 	fclose(str);
12259c2daa00SOllivier Robert 	if (debug)
12269c2daa00SOllivier Robert 		RSA_print_fp(stdout, rsa, 0);
12279c2daa00SOllivier Robert 	fslink(id, trustname);
12289c2daa00SOllivier Robert 	return (pkey);
12299c2daa00SOllivier Robert }
12309c2daa00SOllivier Robert 
12319c2daa00SOllivier Robert 
12329c2daa00SOllivier Robert /*
12339c2daa00SOllivier Robert  * Generate Mu-Varadharajan (MV) parameters and keys
12349c2daa00SOllivier Robert  *
12359c2daa00SOllivier Robert  * The Mu-Varadharajan (MV) cryptosystem is useful when servers
12369c2daa00SOllivier Robert  * broadcast messages to clients, but clients never send messages to
12379c2daa00SOllivier Robert  * servers. There is one encryption key for the server and a separate
12389c2daa00SOllivier Robert  * decryption key for each client. It operates something like a
12399c2daa00SOllivier Robert  * pay-per-view satellite broadcasting system where the session key is
12409c2daa00SOllivier Robert  * encrypted by the broadcaster and the decryption keys are held in a
12419c2daa00SOllivier Robert  * tamperproof set-top box. We don't use it this way, but read on.
12429c2daa00SOllivier Robert  *
12439c2daa00SOllivier Robert  * The MV parameters and private encryption key hide in a DSA cuckoo
12449c2daa00SOllivier Robert  * structure which uses the same parameters, but generated in a
12459c2daa00SOllivier Robert  * different way. The values are used in an encryption scheme similar to
12469c2daa00SOllivier Robert  * El Gamal cryptography and a polynomial formed from the expansion of
12479c2daa00SOllivier Robert  * product terms (x - x[j]), as described in Mu, Y., and V.
12489c2daa00SOllivier Robert  * Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001,
12499c2daa00SOllivier Robert  * 223-231. The paper has significant errors and serious omissions.
12509c2daa00SOllivier Robert  *
12519c2daa00SOllivier Robert  * Let q be the product of n distinct primes s'[j] (j = 1...n), where
12529c2daa00SOllivier Robert  * each s'[j] has m significant bits. Let p be a prime p = 2 * q + 1, so
12539c2daa00SOllivier Robert  * that q and each s'[j] divide p - 1 and p has M = n * m + 1
12549c2daa00SOllivier Robert  * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1)
12559c2daa00SOllivier Robert  * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then
12569c2daa00SOllivier Robert  * project into Zp* as exponents of g. Sometimes we have to compute an
12579c2daa00SOllivier Robert  * inverse b^-1 of random b in Zq, but for that purpose we require
12589c2daa00SOllivier Robert  * gcd(b, q) = 1. We expect M to be in the 500-bit range and n
12599c2daa00SOllivier Robert  * relatively small, like 30. Associated with each s'[j] is an element
12609c2daa00SOllivier Robert  * s[j] such that s[j] s'[j] = s'[j] mod q. We find s[j] as the quotient
12619c2daa00SOllivier Robert  * (q + s'[j]) / s'[j]. These are the parameters of the scheme and they
12629c2daa00SOllivier Robert  * are expensive to compute.
12639c2daa00SOllivier Robert  *
12649c2daa00SOllivier Robert  * We set up an instance of the scheme as follows. A set of random
12659c2daa00SOllivier Robert  * values x[j] mod q (j = 1...n), are generated as the zeros of a
12669c2daa00SOllivier Robert  * polynomial of order n. The product terms (x - x[j]) are expanded to
12679c2daa00SOllivier Robert  * form coefficients a[i] mod q (i = 0...n) in powers of x. These are
12689c2daa00SOllivier Robert  * used as exponents of the generator g mod p to generate the private
12699c2daa00SOllivier Robert  * encryption key A. The pair (gbar, ghat) of public server keys and the
12709c2daa00SOllivier Robert  * pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used
12719c2daa00SOllivier Robert  * to construct the decryption keys. The devil is in the details.
12729c2daa00SOllivier Robert  *
12739c2daa00SOllivier Robert  * This routine generates a private encryption file including the
12749c2daa00SOllivier Robert  * private encryption key E and public key (gbar, ghat). It then
12759c2daa00SOllivier Robert  * generates decryption files including the private key (xbar[j],
12769c2daa00SOllivier Robert  * xhat[j]) for each client. E is a permutation that encrypts a block
12779c2daa00SOllivier Robert  * y = E x. The jth client computes the inverse permutation E^-1 =
12789c2daa00SOllivier Robert  * gbar^xhat[j] ghat^xbar[j] and decrypts the block x = E^-1 y.
12799c2daa00SOllivier Robert  *
12809c2daa00SOllivier Robert  * The distinguishing characteristic of this scheme is the capability to
12819c2daa00SOllivier Robert  * revoke keys. Included in the calculation of E, gbar and ghat is the
12829c2daa00SOllivier Robert  * product s = prod(s'[j]) (j = 1...n) above. If the factor s'[j] is
12839c2daa00SOllivier Robert  * subsequently removed from the product and E, gbar and ghat
12849c2daa00SOllivier Robert  * recomputed, the jth client will no longer be able to compute E^-1 and
12859c2daa00SOllivier Robert  * thus unable to decrypt the block.
12869c2daa00SOllivier Robert  */
12879c2daa00SOllivier Robert EVP_PKEY *			/* DSA cuckoo nest */
12889c2daa00SOllivier Robert gen_mv(
12899c2daa00SOllivier Robert 	char	*id		/* file name id */
12909c2daa00SOllivier Robert 	)
12919c2daa00SOllivier Robert {
12925e91a9b7SOllivier Robert 	EVP_PKEY *pkey, *pkey1;	/* private key */
12939c2daa00SOllivier Robert 	DSA	*dsa;		/* DSA parameters */
12949c2daa00SOllivier Robert 	DSA	*sdsa;		/* DSA parameters */
12959c2daa00SOllivier Robert 	BN_CTX	*ctx;		/* BN working space */
12969c2daa00SOllivier Robert 	BIGNUM	**x;		/* polynomial zeros vector */
12979c2daa00SOllivier Robert 	BIGNUM	**a;		/* polynomial coefficient vector */
12989c2daa00SOllivier Robert 	BIGNUM	**g;		/* public key vector */
12999c2daa00SOllivier Robert 	BIGNUM	**s, **s1;	/* private enabling keys */
13009c2daa00SOllivier Robert 	BIGNUM	**xbar, **xhat;	/* private keys vector */
13019c2daa00SOllivier Robert 	BIGNUM	*b;		/* group key */
13029c2daa00SOllivier Robert 	BIGNUM	*b1;		/* inverse group key */
13039c2daa00SOllivier Robert 	BIGNUM	*ss;		/* enabling key */
13049c2daa00SOllivier Robert 	BIGNUM	*biga;		/* master encryption key */
13059c2daa00SOllivier Robert 	BIGNUM	*bige;		/* session encryption key */
13069c2daa00SOllivier Robert 	BIGNUM	*gbar, *ghat;	/* public key */
13079c2daa00SOllivier Robert 	BIGNUM	*u, *v, *w;	/* BN scratch */
13089c2daa00SOllivier Robert 	int	i, j, n;
13099c2daa00SOllivier Robert 	FILE	*str;
13109c2daa00SOllivier Robert 	u_int	temp;
13119c2daa00SOllivier Robert 	char	ident[20];
13129c2daa00SOllivier Robert 
13139c2daa00SOllivier Robert 	/*
13149c2daa00SOllivier Robert 	 * Generate MV parameters.
13159c2daa00SOllivier Robert 	 *
13169c2daa00SOllivier Robert 	 * The object is to generate a multiplicative group Zp* modulo a
13179c2daa00SOllivier Robert 	 * prime p and a subset Zq mod q, where q is the product of n
13189c2daa00SOllivier Robert 	 * distinct primes s'[j] (j = 1...n) and q divides p - 1. We
13199c2daa00SOllivier Robert 	 * first generate n distinct primes, which may have to be
13209c2daa00SOllivier Robert 	 * regenerated later. As a practical matter, it is tough to find
13219c2daa00SOllivier Robert 	 * more than 31 distinct primes for modulus 512 or 61 primes for
13229c2daa00SOllivier Robert 	 * modulus 1024. The latter can take several hundred iterations
13239c2daa00SOllivier Robert 	 * and several minutes on a Sun Blade 1000.
13249c2daa00SOllivier Robert 	 */
13259c2daa00SOllivier Robert 	n = nkeys;
13269c2daa00SOllivier Robert 	fprintf(stderr,
13279c2daa00SOllivier Robert 	    "Generating MV parameters for %d keys (%d bits)...\n", n,
13289c2daa00SOllivier Robert 	    modulus / n);
13299c2daa00SOllivier Robert 	ctx = BN_CTX_new(); u = BN_new(); v = BN_new(); w = BN_new();
13309c2daa00SOllivier Robert 	b = BN_new(); b1 = BN_new();
13315e91a9b7SOllivier Robert 	dsa = DSA_new();
13329c2daa00SOllivier Robert 	dsa->p = BN_new();
13339c2daa00SOllivier Robert 	dsa->q = BN_new();
13349c2daa00SOllivier Robert 	dsa->g = BN_new();
13359c2daa00SOllivier Robert 	s = malloc((n + 1) * sizeof(BIGNUM));
13369c2daa00SOllivier Robert 	s1 = malloc((n + 1) * sizeof(BIGNUM));
13379c2daa00SOllivier Robert 	for (j = 1; j <= n; j++)
13389c2daa00SOllivier Robert 		s1[j] = BN_new();
13399c2daa00SOllivier Robert 	temp = 0;
13409c2daa00SOllivier Robert 	for (j = 1; j <= n; j++) {
13419c2daa00SOllivier Robert 		while (1) {
13429c2daa00SOllivier Robert 			fprintf(stderr, "Birthdays %d\r", temp);
13439c2daa00SOllivier Robert 			BN_generate_prime(s1[j], modulus / n, 0, NULL,
13449c2daa00SOllivier Robert 			    NULL, NULL, NULL);
13459c2daa00SOllivier Robert 			for (i = 1; i < j; i++) {
13469c2daa00SOllivier Robert 				if (BN_cmp(s1[i], s1[j]) == 0)
13479c2daa00SOllivier Robert 					break;
13489c2daa00SOllivier Robert 			}
13499c2daa00SOllivier Robert 			if (i == j)
13509c2daa00SOllivier Robert 				break;
13519c2daa00SOllivier Robert 			temp++;
13529c2daa00SOllivier Robert 		}
13539c2daa00SOllivier Robert 	}
13549c2daa00SOllivier Robert 	fprintf(stderr, "Birthday keys rejected %d\n", temp);
13559c2daa00SOllivier Robert 
13569c2daa00SOllivier Robert 	/*
13579c2daa00SOllivier Robert 	 * Compute the modulus q as the product of the primes. Compute
13589c2daa00SOllivier Robert 	 * the modulus p as 2 * q + 1 and test p for primality. If p
13599c2daa00SOllivier Robert 	 * is composite, replace one of the primes with a new distinct
13609c2daa00SOllivier Robert 	 * one and try again. Note that q will hardly be a secret since
13619c2daa00SOllivier Robert 	 * we have to reveal p to servers and clients. However,
13629c2daa00SOllivier Robert 	 * factoring q to find the primes should be adequately hard, as
13639c2daa00SOllivier Robert 	 * this is the same problem considered hard in RSA. Question: is
13649c2daa00SOllivier Robert 	 * it as hard to find n small prime factors totalling n bits as
13659c2daa00SOllivier Robert 	 * it is to find two large prime factors totalling n bits?
13669c2daa00SOllivier Robert 	 * Remember, the bad guy doesn't know n.
13679c2daa00SOllivier Robert 	 */
13689c2daa00SOllivier Robert 	temp = 0;
13699c2daa00SOllivier Robert 	while (1) {
13709c2daa00SOllivier Robert 		fprintf(stderr, "Duplicate keys rejected %d\r", ++temp);
13719c2daa00SOllivier Robert 		BN_one(dsa->q);
13729c2daa00SOllivier Robert 		for (j = 1; j <= n; j++)
13739c2daa00SOllivier Robert 			BN_mul(dsa->q, dsa->q, s1[j], ctx);
13749c2daa00SOllivier Robert 		BN_copy(dsa->p, dsa->q);
13759c2daa00SOllivier Robert 		BN_add(dsa->p, dsa->p, dsa->p);
13769c2daa00SOllivier Robert 		BN_add_word(dsa->p, 1);
13779c2daa00SOllivier Robert 		if (BN_is_prime(dsa->p, BN_prime_checks, NULL, ctx,
13789c2daa00SOllivier Robert 		    NULL))
13799c2daa00SOllivier Robert 			break;
13809c2daa00SOllivier Robert 
13819c2daa00SOllivier Robert 		j = temp % n + 1;
13829c2daa00SOllivier Robert 		while (1) {
13839c2daa00SOllivier Robert 			BN_generate_prime(u, modulus / n, 0, 0, NULL,
13849c2daa00SOllivier Robert 			    NULL, NULL);
13859c2daa00SOllivier Robert 			for (i = 1; i <= n; i++) {
13869c2daa00SOllivier Robert 				if (BN_cmp(u, s1[i]) == 0)
13879c2daa00SOllivier Robert 					break;
13889c2daa00SOllivier Robert 			}
13899c2daa00SOllivier Robert 			if (i > n)
13909c2daa00SOllivier Robert 				break;
13919c2daa00SOllivier Robert 		}
13929c2daa00SOllivier Robert 		BN_copy(s1[j], u);
13939c2daa00SOllivier Robert 	}
13949c2daa00SOllivier Robert 	fprintf(stderr, "Duplicate keys rejected %d\n", temp);
13959c2daa00SOllivier Robert 
13969c2daa00SOllivier Robert 	/*
13979c2daa00SOllivier Robert 	 * Compute the generator g using a random roll such that
13989c2daa00SOllivier Robert 	 * gcd(g, p - 1) = 1 and g^q = 1. This is a generator of p, not
13999c2daa00SOllivier Robert 	 * q.
14009c2daa00SOllivier Robert 	 */
14019c2daa00SOllivier Robert 	BN_copy(v, dsa->p);
14029c2daa00SOllivier Robert 	BN_sub_word(v, 1);
14039c2daa00SOllivier Robert 	while (1) {
14049c2daa00SOllivier Robert 		BN_rand(dsa->g, BN_num_bits(dsa->p) - 1, 0, 0);
14059c2daa00SOllivier Robert 		BN_mod(dsa->g, dsa->g, dsa->p, ctx);
14069c2daa00SOllivier Robert 		BN_gcd(u, dsa->g, v, ctx);
14079c2daa00SOllivier Robert 		if (!BN_is_one(u))
14089c2daa00SOllivier Robert 			continue;
14099c2daa00SOllivier Robert 
14109c2daa00SOllivier Robert 		BN_mod_exp(u, dsa->g, dsa->q, dsa->p, ctx);
14119c2daa00SOllivier Robert 		if (BN_is_one(u))
14129c2daa00SOllivier Robert 			break;
14139c2daa00SOllivier Robert 	}
14149c2daa00SOllivier Robert 
14159c2daa00SOllivier Robert 	/*
14169c2daa00SOllivier Robert 	 * Compute s[j] such that s[j] * s'[j] = s'[j] for all j. The
14179c2daa00SOllivier Robert 	 * easy way to do this is to compute q + s'[j] and divide the
14189c2daa00SOllivier Robert 	 * result by s'[j]. Exercise for the student: prove the
14199c2daa00SOllivier Robert 	 * remainder is always zero.
14209c2daa00SOllivier Robert 	 */
14219c2daa00SOllivier Robert 	for (j = 1; j <= n; j++) {
14229c2daa00SOllivier Robert 		s[j] = BN_new();
14239c2daa00SOllivier Robert 		BN_add(s[j], dsa->q, s1[j]);
14249c2daa00SOllivier Robert 		BN_div(s[j], u, s[j], s1[j], ctx);
14259c2daa00SOllivier Robert 	}
14269c2daa00SOllivier Robert 
14279c2daa00SOllivier Robert 	/*
14289c2daa00SOllivier Robert 	 * Setup is now complete. Roll random polynomial roots x[j]
14299c2daa00SOllivier Robert 	 * (0 < x[j] < q) for all j. While it may not be strictly
14309c2daa00SOllivier Robert 	 * necessary, Make sure each root has no factors in common with
14319c2daa00SOllivier Robert 	 * q.
14329c2daa00SOllivier Robert 	 */
14339c2daa00SOllivier Robert 	fprintf(stderr,
14349c2daa00SOllivier Robert 	    "Generating polynomial coefficients for %d roots (%d bits)\n",
14359c2daa00SOllivier Robert 	    n, BN_num_bits(dsa->q));
14369c2daa00SOllivier Robert 	x = malloc((n + 1) * sizeof(BIGNUM));
14379c2daa00SOllivier Robert 	for (j = 1; j <= n; j++) {
14389c2daa00SOllivier Robert 		x[j] = BN_new();
14399c2daa00SOllivier Robert 		while (1) {
14409c2daa00SOllivier Robert 			BN_rand(x[j], BN_num_bits(dsa->q), 0, 0);
14419c2daa00SOllivier Robert 			BN_mod(x[j], x[j], dsa->q, ctx);
14429c2daa00SOllivier Robert 			BN_gcd(u, x[j], dsa->q, ctx);
14439c2daa00SOllivier Robert 			if (BN_is_one(u))
14449c2daa00SOllivier Robert 				break;
14459c2daa00SOllivier Robert 		}
14469c2daa00SOllivier Robert 	}
14479c2daa00SOllivier Robert 
14489c2daa00SOllivier Robert 	/*
14499c2daa00SOllivier Robert 	 * Generate polynomial coefficients a[i] (i = 0...n) from the
14509c2daa00SOllivier Robert 	 * expansion of root products (x - x[j]) mod q for all j. The
14519c2daa00SOllivier Robert 	 * method is a present from Charlie Boncelet.
14529c2daa00SOllivier Robert 	 */
14539c2daa00SOllivier Robert 	a = malloc((n + 1) * sizeof(BIGNUM));
14549c2daa00SOllivier Robert 	for (i = 0; i <= n; i++) {
14559c2daa00SOllivier Robert 		a[i] = BN_new();
14569c2daa00SOllivier Robert 		BN_one(a[i]);
14579c2daa00SOllivier Robert 	}
14589c2daa00SOllivier Robert 	for (j = 1; j <= n; j++) {
14599c2daa00SOllivier Robert 		BN_zero(w);
14609c2daa00SOllivier Robert 		for (i = 0; i < j; i++) {
14619c2daa00SOllivier Robert 			BN_copy(u, dsa->q);
14629c2daa00SOllivier Robert 			BN_mod_mul(v, a[i], x[j], dsa->q, ctx);
14639c2daa00SOllivier Robert 			BN_sub(u, u, v);
14649c2daa00SOllivier Robert 			BN_add(u, u, w);
14659c2daa00SOllivier Robert 			BN_copy(w, a[i]);
14669c2daa00SOllivier Robert 			BN_mod(a[i], u, dsa->q, ctx);
14679c2daa00SOllivier Robert 		}
14689c2daa00SOllivier Robert 	}
14699c2daa00SOllivier Robert 
14709c2daa00SOllivier Robert 	/*
14719c2daa00SOllivier Robert 	 * Generate g[i] = g^a[i] mod p for all i and the generator g.
14729c2daa00SOllivier Robert 	 */
14739c2daa00SOllivier Robert 	fprintf(stderr, "Generating g[i] parameters\n");
14749c2daa00SOllivier Robert 	g = malloc((n + 1) * sizeof(BIGNUM));
14759c2daa00SOllivier Robert 	for (i = 0; i <= n; i++) {
14769c2daa00SOllivier Robert 		g[i] = BN_new();
14779c2daa00SOllivier Robert 		BN_mod_exp(g[i], dsa->g, a[i], dsa->p, ctx);
14789c2daa00SOllivier Robert 	}
14799c2daa00SOllivier Robert 
14809c2daa00SOllivier Robert 	/*
14819c2daa00SOllivier Robert 	 * Verify prod(g[i]^(a[i] x[j]^i)) = 1 for all i, j; otherwise,
14829c2daa00SOllivier Robert 	 * exit. Note the a[i] x[j]^i exponent is computed mod q, but
14839c2daa00SOllivier Robert 	 * the g[i] is computed mod p. also note the expression given in
14849c2daa00SOllivier Robert 	 * the paper is incorrect.
14859c2daa00SOllivier Robert 	 */
14869c2daa00SOllivier Robert 	temp = 1;
14879c2daa00SOllivier Robert 	for (j = 1; j <= n; j++) {
14889c2daa00SOllivier Robert 		BN_one(u);
14899c2daa00SOllivier Robert 		for (i = 0; i <= n; i++) {
14909c2daa00SOllivier Robert 			BN_set_word(v, i);
14919c2daa00SOllivier Robert 			BN_mod_exp(v, x[j], v, dsa->q, ctx);
14929c2daa00SOllivier Robert 			BN_mod_mul(v, v, a[i], dsa->q, ctx);
14939c2daa00SOllivier Robert 			BN_mod_exp(v, dsa->g, v, dsa->p, ctx);
14949c2daa00SOllivier Robert 			BN_mod_mul(u, u, v, dsa->p, ctx);
14959c2daa00SOllivier Robert 		}
14969c2daa00SOllivier Robert 		if (!BN_is_one(u))
14979c2daa00SOllivier Robert 			temp = 0;
14989c2daa00SOllivier Robert 	}
14999c2daa00SOllivier Robert 	fprintf(stderr,
15009c2daa00SOllivier Robert 	    "Confirm prod(g[i]^(x[j]^i)) = 1 for all i, j: %s\n", temp ?
15019c2daa00SOllivier Robert 	    "yes" : "no");
15029c2daa00SOllivier Robert 	if (!temp) {
15039c2daa00SOllivier Robert 		rval = -1;
15049c2daa00SOllivier Robert 		return (NULL);
15059c2daa00SOllivier Robert 	}
15069c2daa00SOllivier Robert 
15079c2daa00SOllivier Robert 	/*
15089c2daa00SOllivier Robert 	 * Make private encryption key A. Keep it around for awhile,
15099c2daa00SOllivier Robert 	 * since it is expensive to compute.
15109c2daa00SOllivier Robert 	 */
15119c2daa00SOllivier Robert 	biga = BN_new();
15129c2daa00SOllivier Robert 	BN_one(biga);
15139c2daa00SOllivier Robert 	for (j = 1; j <= n; j++) {
15149c2daa00SOllivier Robert 		for (i = 0; i < n; i++) {
15159c2daa00SOllivier Robert 			BN_set_word(v, i);
15169c2daa00SOllivier Robert 			BN_mod_exp(v, x[j], v, dsa->q, ctx);
15179c2daa00SOllivier Robert 			BN_mod_exp(v, g[i], v, dsa->p, ctx);
15189c2daa00SOllivier Robert 			BN_mod_mul(biga, biga, v, dsa->p, ctx);
15199c2daa00SOllivier Robert 		}
15209c2daa00SOllivier Robert 	}
15219c2daa00SOllivier Robert 
15229c2daa00SOllivier Robert 	/*
15239c2daa00SOllivier Robert 	 * Roll private random group key b mod q (0 < b < q), where
15249c2daa00SOllivier Robert 	 * gcd(b, q) = 1 to guarantee b^1 exists, then compute b^-1
15259c2daa00SOllivier Robert 	 * mod q. If b is changed, the client keys must be recomputed.
15269c2daa00SOllivier Robert 	 */
15279c2daa00SOllivier Robert 	while (1) {
15289c2daa00SOllivier Robert 		BN_rand(b, BN_num_bits(dsa->q), 0, 0);
15299c2daa00SOllivier Robert 		BN_mod(b, b, dsa->q, ctx);
15309c2daa00SOllivier Robert 		BN_gcd(u, b, dsa->q, ctx);
15319c2daa00SOllivier Robert 		if (BN_is_one(u))
15329c2daa00SOllivier Robert 			break;
15339c2daa00SOllivier Robert 	}
15349c2daa00SOllivier Robert 	BN_mod_inverse(b1, b, dsa->q, ctx);
15359c2daa00SOllivier Robert 
15369c2daa00SOllivier Robert 	/*
15379c2daa00SOllivier Robert 	 * Make private client keys (xbar[j], xhat[j]) for all j. Note
15389c2daa00SOllivier Robert 	 * that the keys for the jth client involve s[j], but not s'[j]
15399c2daa00SOllivier Robert 	 * or the product s = prod(s'[j]) mod q, which is the enabling
15409c2daa00SOllivier Robert 	 * key.
15419c2daa00SOllivier Robert 	 */
15429c2daa00SOllivier Robert 	xbar = malloc((n + 1) * sizeof(BIGNUM));
15439c2daa00SOllivier Robert 	xhat = malloc((n + 1) * sizeof(BIGNUM));
15449c2daa00SOllivier Robert 	for (j = 1; j <= n; j++) {
15459c2daa00SOllivier Robert 		xbar[j] = BN_new(); xhat[j] = BN_new();
15469c2daa00SOllivier Robert 		BN_zero(xbar[j]);
15479c2daa00SOllivier Robert 		BN_set_word(v, n);
15489c2daa00SOllivier Robert 		for (i = 1; i <= n; i++) {
15499c2daa00SOllivier Robert 			if (i == j)
15509c2daa00SOllivier Robert 				continue;
15519c2daa00SOllivier Robert 			BN_mod_exp(u, x[i], v, dsa->q, ctx);
15529c2daa00SOllivier Robert 			BN_add(xbar[j], xbar[j], u);
15539c2daa00SOllivier Robert 		}
15549c2daa00SOllivier Robert 		BN_mod_mul(xbar[j], xbar[j], b1, dsa->q, ctx);
15559c2daa00SOllivier Robert 		BN_mod_exp(xhat[j], x[j], v, dsa->q, ctx);
15569c2daa00SOllivier Robert 		BN_mod_mul(xhat[j], xhat[j], s[j], dsa->q, ctx);
15579c2daa00SOllivier Robert 	}
15589c2daa00SOllivier Robert 
15599c2daa00SOllivier Robert 	/*
15609c2daa00SOllivier Robert 	 * The enabling key is initially q by construction. We can
15619c2daa00SOllivier Robert 	 * revoke client j by dividing q by s'[j]. The quotient becomes
15629c2daa00SOllivier Robert 	 * the enabling key s. Note we always have to revoke one key;
15639c2daa00SOllivier Robert 	 * otherwise, the plaintext and cryptotext would be identical.
15649c2daa00SOllivier Robert 	 */
15659c2daa00SOllivier Robert 	ss = BN_new();
15669c2daa00SOllivier Robert 	BN_copy(ss, dsa->q);
15679c2daa00SOllivier Robert 	BN_div(ss, u, dsa->q, s1[n], ctx);
15689c2daa00SOllivier Robert 
15699c2daa00SOllivier Robert 	/*
15709c2daa00SOllivier Robert 	 * Make private server encryption key E = A^s and public server
15719c2daa00SOllivier Robert 	 * keys gbar = g^s mod p and ghat = g^(s b) mod p. The (gbar,
15729c2daa00SOllivier Robert 	 * ghat) is the public key provided to the server, which uses it
15739c2daa00SOllivier Robert 	 * to compute the session encryption key and public key included
15749c2daa00SOllivier Robert 	 * in its messages. These values must be regenerated if the
15759c2daa00SOllivier Robert 	 * enabling key is changed.
15769c2daa00SOllivier Robert 	 */
15779c2daa00SOllivier Robert 	bige = BN_new(); gbar = BN_new(); ghat = BN_new();
15789c2daa00SOllivier Robert 	BN_mod_exp(bige, biga, ss, dsa->p, ctx);
15799c2daa00SOllivier Robert 	BN_mod_exp(gbar, dsa->g, ss, dsa->p, ctx);
15809c2daa00SOllivier Robert 	BN_mod_mul(v, ss, b, dsa->q, ctx);
15819c2daa00SOllivier Robert 	BN_mod_exp(ghat, dsa->g, v, dsa->p, ctx);
15829c2daa00SOllivier Robert 
15839c2daa00SOllivier Robert 	/*
15849c2daa00SOllivier Robert 	 * We produce the key media in three steps. The first step is to
15859c2daa00SOllivier Robert 	 * generate the private values that do not depend on the
15869c2daa00SOllivier Robert 	 * enabling key. These include the server values p, q, g, b, A
15879c2daa00SOllivier Robert 	 * and the client values s'[j], xbar[j] and xhat[j] for each j.
15889c2daa00SOllivier Robert 	 * The p, xbar[j] and xhat[j] values are encoded in private
15899c2daa00SOllivier Robert 	 * files which are distributed to respective clients. The p, q,
15909c2daa00SOllivier Robert 	 * g, A and s'[j] values (will be) written to a secret file to
15919c2daa00SOllivier Robert 	 * be read back later.
15929c2daa00SOllivier Robert 	 *
15939c2daa00SOllivier Robert 	 * The secret file (will be) read back at some later time to
15949c2daa00SOllivier Robert 	 * enable/disable individual keys and generate/regenerate the
15959c2daa00SOllivier Robert 	 * enabling key s. The p, q, E, gbar and ghat values are written
15969c2daa00SOllivier Robert 	 * to a secret file to be read back later by the server.
15979c2daa00SOllivier Robert 	 *
15989c2daa00SOllivier Robert 	 * The server reads the secret file and rolls the session key
15999c2daa00SOllivier Robert 	 * k, which is used only once, then computes E^k, gbar^k and
16009c2daa00SOllivier Robert 	 * ghat^k. The E^k is the session encryption key. The encrypted
16019c2daa00SOllivier Robert 	 * data, gbar^k and ghat^k are transmtted to clients in an
16029c2daa00SOllivier Robert 	 * extension field. The client receives the message and computes
16039c2daa00SOllivier Robert 	 * x = (gbar^k)^xbar[j] (ghat^k)^xhat[j], finds the session
16049c2daa00SOllivier Robert 	 * encryption key E^k as the inverse x^-1 and decrypts the data.
16059c2daa00SOllivier Robert 	 */
16069c2daa00SOllivier Robert 	BN_copy(dsa->g, bige);
16079c2daa00SOllivier Robert 	dsa->priv_key = BN_dup(gbar);
16089c2daa00SOllivier Robert 	dsa->pub_key = BN_dup(ghat);
16099c2daa00SOllivier Robert 
16109c2daa00SOllivier Robert 	/*
16119c2daa00SOllivier Robert 	 * Write the MV server parameters and keys as a DSA private key
16129c2daa00SOllivier Robert 	 * encoded in PEM.
16139c2daa00SOllivier Robert 	 *
16149c2daa00SOllivier Robert 	 * p	modulus p
16159c2daa00SOllivier Robert 	 * q	modulus q (used only to generate k)
16169c2daa00SOllivier Robert 	 * g	E mod p
16179c2daa00SOllivier Robert 	 * priv_key gbar mod p
16189c2daa00SOllivier Robert 	 * pub_key ghat mod p
16199c2daa00SOllivier Robert 	 */
16209c2daa00SOllivier Robert 	str = fheader("MVpar", trustname);
16219c2daa00SOllivier Robert 	pkey = EVP_PKEY_new();
16229c2daa00SOllivier Robert 	EVP_PKEY_assign_DSA(pkey, dsa);
16239c2daa00SOllivier Robert 	PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL,
16249c2daa00SOllivier Robert 	    NULL, 0, NULL, passwd2);
16259c2daa00SOllivier Robert 	fclose(str);
16269c2daa00SOllivier Robert 	if (debug)
16279c2daa00SOllivier Robert 		DSA_print_fp(stdout, dsa, 0);
16289c2daa00SOllivier Robert 	fslink(id, trustname);
16299c2daa00SOllivier Robert 
16309c2daa00SOllivier Robert 	/*
16319c2daa00SOllivier Robert 	 * Write the parameters and private key (xbar[j], xhat[j]) for
16329c2daa00SOllivier Robert 	 * all j as a DSA private key encoded in PEM. It is used only by
16339c2daa00SOllivier Robert 	 * the designated recipient(s) who pay a suitably outrageous fee
16349c2daa00SOllivier Robert 	 * for its use.
16359c2daa00SOllivier Robert 	 */
16365e91a9b7SOllivier Robert 	sdsa = DSA_new();
16379c2daa00SOllivier Robert 	sdsa->p = BN_dup(dsa->p);
16389c2daa00SOllivier Robert 	sdsa->q = BN_dup(BN_value_one());
16399c2daa00SOllivier Robert 	sdsa->g = BN_dup(BN_value_one());
16409c2daa00SOllivier Robert 	sdsa->priv_key = BN_new();
16419c2daa00SOllivier Robert 	sdsa->pub_key = BN_new();
16429c2daa00SOllivier Robert 	for (j = 1; j <= n; j++) {
16439c2daa00SOllivier Robert 		BN_copy(sdsa->priv_key, xbar[j]);
16449c2daa00SOllivier Robert 		BN_copy(sdsa->pub_key, xhat[j]);
16459c2daa00SOllivier Robert 		BN_mod_exp(v, dsa->priv_key, sdsa->pub_key, dsa->p,
16469c2daa00SOllivier Robert 		    ctx);
16479c2daa00SOllivier Robert 		BN_mod_exp(u, dsa->pub_key, sdsa->priv_key, dsa->p,
16489c2daa00SOllivier Robert 		    ctx);
16499c2daa00SOllivier Robert 		BN_mod_mul(u, u, v, dsa->p, ctx);
16509c2daa00SOllivier Robert 		BN_mod_mul(u, u, dsa->g, dsa->p, ctx);
16519c2daa00SOllivier Robert 		BN_free(xbar[j]); BN_free(xhat[j]);
16529c2daa00SOllivier Robert 		BN_free(x[j]); BN_free(s[j]); BN_free(s1[j]);
16539c2daa00SOllivier Robert 		if (!BN_is_one(u)) {
16549c2daa00SOllivier Robert 			fprintf(stderr, "Revoke key %d\n", j);
16559c2daa00SOllivier Robert 			continue;
16569c2daa00SOllivier Robert 		}
16579c2daa00SOllivier Robert 
16589c2daa00SOllivier Robert 		/*
16599c2daa00SOllivier Robert 		 * Write the client parameters as a DSA private key
16609c2daa00SOllivier Robert 		 * encoded in PEM. We don't make links for these.
16619c2daa00SOllivier Robert 		 *
16629c2daa00SOllivier Robert 		 * p	modulus p
16639c2daa00SOllivier Robert 		 * priv_key xbar[j] mod q
16649c2daa00SOllivier Robert 		 * pub_key xhat[j] mod q
16659c2daa00SOllivier Robert 		 * (remaining values are not used)
16669c2daa00SOllivier Robert 		 */
16679c2daa00SOllivier Robert 		sprintf(ident, "MVkey%d", j);
16689c2daa00SOllivier Robert 		str = fheader(ident, trustname);
16695e91a9b7SOllivier Robert 		pkey1 = EVP_PKEY_new();
16705e91a9b7SOllivier Robert 		EVP_PKEY_set1_DSA(pkey1, sdsa);
16715e91a9b7SOllivier Robert 		PEM_write_PrivateKey(str, pkey1, passwd2 ?
16729c2daa00SOllivier Robert 		    EVP_des_cbc() : NULL, NULL, 0, NULL, passwd2);
16739c2daa00SOllivier Robert 		fclose(str);
16749c2daa00SOllivier Robert 		fprintf(stderr, "ntpkey_%s_%s.%lu\n", ident, trustname,
16759c2daa00SOllivier Robert 		    epoch + JAN_1970);
16769c2daa00SOllivier Robert 		if (debug)
16779c2daa00SOllivier Robert 			DSA_print_fp(stdout, sdsa, 0);
16785e91a9b7SOllivier Robert 		EVP_PKEY_free(pkey1);
16799c2daa00SOllivier Robert 	}
16809c2daa00SOllivier Robert 
16819c2daa00SOllivier Robert 	/*
16829c2daa00SOllivier Robert 	 * Free the countries.
16839c2daa00SOllivier Robert 	 */
16849c2daa00SOllivier Robert 	for (i = 0; i <= n; i++) {
16859c2daa00SOllivier Robert 		BN_free(a[i]);
16869c2daa00SOllivier Robert 		BN_free(g[i]);
16879c2daa00SOllivier Robert 	}
16889c2daa00SOllivier Robert 	BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx);
16899c2daa00SOllivier Robert 	BN_free(b); BN_free(b1); BN_free(biga); BN_free(bige);
16909c2daa00SOllivier Robert 	BN_free(ss); BN_free(gbar); BN_free(ghat);
16915e91a9b7SOllivier Robert 	DSA_free(sdsa);
16929c2daa00SOllivier Robert 
16939c2daa00SOllivier Robert 	/*
16949c2daa00SOllivier Robert 	 * Free the world.
16959c2daa00SOllivier Robert 	 */
16969c2daa00SOllivier Robert 	free(x); free(a); free(g); free(s); free(s1);
16979c2daa00SOllivier Robert 	free(xbar); free(xhat);
16989c2daa00SOllivier Robert 	return (pkey);
16999c2daa00SOllivier Robert }
17009c2daa00SOllivier Robert 
17019c2daa00SOllivier Robert 
17029c2daa00SOllivier Robert /*
17039c2daa00SOllivier Robert  * Generate X509v3 scertificate.
17049c2daa00SOllivier Robert  *
17059c2daa00SOllivier Robert  * The certificate consists of the version number, serial number,
17069c2daa00SOllivier Robert  * validity interval, issuer name, subject name and public key. For a
17079c2daa00SOllivier Robert  * self-signed certificate, the issuer name is the same as the subject
17089c2daa00SOllivier Robert  * name and these items are signed using the subject private key. The
17099c2daa00SOllivier Robert  * validity interval extends from the current time to the same time one
17109c2daa00SOllivier Robert  * year hence. For NTP purposes, it is convenient to use the NTP seconds
17119c2daa00SOllivier Robert  * of the current time as the serial number.
17129c2daa00SOllivier Robert  */
17139c2daa00SOllivier Robert int
17149c2daa00SOllivier Robert x509	(
17159c2daa00SOllivier Robert 	EVP_PKEY *pkey,		/* generic signature algorithm */
17169c2daa00SOllivier Robert 	const EVP_MD *md,	/* generic digest algorithm */
17179c2daa00SOllivier Robert 	char	*gqpub,		/* identity extension (hex string) */
17189c2daa00SOllivier Robert 	char	*exten		/* private cert extension */
17199c2daa00SOllivier Robert 	)
17209c2daa00SOllivier Robert {
17219c2daa00SOllivier Robert 	X509	*cert;		/* X509 certificate */
17229c2daa00SOllivier Robert 	X509_NAME *subj;	/* distinguished (common) name */
17239c2daa00SOllivier Robert 	X509_EXTENSION *ex;	/* X509v3 extension */
17249c2daa00SOllivier Robert 	FILE	*str;		/* file handle */
17259c2daa00SOllivier Robert 	ASN1_INTEGER *serial;	/* serial number */
17269c2daa00SOllivier Robert 	const char *id;		/* digest/signature scheme name */
17279c2daa00SOllivier Robert 	char	pathbuf[MAXFILENAME + 1];
17289c2daa00SOllivier Robert 
17299c2daa00SOllivier Robert 	/*
17309c2daa00SOllivier Robert 	 * Generate X509 self-signed certificate.
17319c2daa00SOllivier Robert 	 *
17329c2daa00SOllivier Robert 	 * Set the certificate serial to the NTP seconds for grins. Set
17339c2daa00SOllivier Robert 	 * the version to 3. Set the subject name and issuer name to the
17349c2daa00SOllivier Robert 	 * subject name in the request. Set the initial validity to the
17359c2daa00SOllivier Robert 	 * current time and the final validity one year hence.
17369c2daa00SOllivier Robert 	 */
17379c2daa00SOllivier Robert 	id = OBJ_nid2sn(md->pkey_type);
17389c2daa00SOllivier Robert 	fprintf(stderr, "Generating certificate %s\n", id);
17399c2daa00SOllivier Robert 	cert = X509_new();
17409c2daa00SOllivier Robert 	X509_set_version(cert, 2L);
17419c2daa00SOllivier Robert 	serial = ASN1_INTEGER_new();
17429c2daa00SOllivier Robert 	ASN1_INTEGER_set(serial, epoch + JAN_1970);
17439c2daa00SOllivier Robert 	X509_set_serialNumber(cert, serial);
17449c2daa00SOllivier Robert 	ASN1_INTEGER_free(serial);
17459c2daa00SOllivier Robert 	X509_gmtime_adj(X509_get_notBefore(cert), 0L);
17469c2daa00SOllivier Robert 	X509_gmtime_adj(X509_get_notAfter(cert), YEAR);
17479c2daa00SOllivier Robert 	subj = X509_get_subject_name(cert);
17489c2daa00SOllivier Robert 	X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
17499c2daa00SOllivier Robert 	    (unsigned char *) hostname, strlen(hostname), -1, 0);
17509c2daa00SOllivier Robert 	subj = X509_get_issuer_name(cert);
17519c2daa00SOllivier Robert 	X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
17529c2daa00SOllivier Robert 	    (unsigned char *) trustname, strlen(trustname), -1, 0);
17539c2daa00SOllivier Robert 	if (!X509_set_pubkey(cert, pkey)) {
17549c2daa00SOllivier Robert 		fprintf(stderr, "Assign key fails\n%s\n",
17559c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
17569c2daa00SOllivier Robert 		X509_free(cert);
17579c2daa00SOllivier Robert 		rval = -1;
17589c2daa00SOllivier Robert 		return (0);
17599c2daa00SOllivier Robert 	}
17609c2daa00SOllivier Robert 
17619c2daa00SOllivier Robert 	/*
17629c2daa00SOllivier Robert 	 * Add X509v3 extensions if present. These represent the minimum
17639c2daa00SOllivier Robert 	 * set defined in RFC3280 less the certificate_policy extension,
17649c2daa00SOllivier Robert 	 * which is seriously obfuscated in OpenSSL.
17659c2daa00SOllivier Robert 	 */
17669c2daa00SOllivier Robert 	/*
17679c2daa00SOllivier Robert 	 * The basic_constraints extension CA:TRUE allows servers to
17689c2daa00SOllivier Robert 	 * sign client certficitates.
17699c2daa00SOllivier Robert 	 */
17709c2daa00SOllivier Robert 	fprintf(stderr, "%s: %s\n", LN_basic_constraints,
17719c2daa00SOllivier Robert 	    BASIC_CONSTRAINTS);
17729c2daa00SOllivier Robert 	ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,
17739c2daa00SOllivier Robert 	    BASIC_CONSTRAINTS);
17749c2daa00SOllivier Robert 	if (!X509_add_ext(cert, ex, -1)) {
17759c2daa00SOllivier Robert 		fprintf(stderr, "Add extension field fails\n%s\n",
17769c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
17779c2daa00SOllivier Robert 		rval = -1;
17789c2daa00SOllivier Robert 		return (0);
17799c2daa00SOllivier Robert 	}
17809c2daa00SOllivier Robert 	X509_EXTENSION_free(ex);
17819c2daa00SOllivier Robert 
17829c2daa00SOllivier Robert 	/*
17839c2daa00SOllivier Robert 	 * The key_usage extension designates the purposes the key can
17849c2daa00SOllivier Robert 	 * be used for.
17859c2daa00SOllivier Robert 	 */
17869c2daa00SOllivier Robert 	fprintf(stderr, "%s: %s\n", LN_key_usage, KEY_USAGE);
17879c2daa00SOllivier Robert 	ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, KEY_USAGE);
17889c2daa00SOllivier Robert 	if (!X509_add_ext(cert, ex, -1)) {
17899c2daa00SOllivier Robert 		fprintf(stderr, "Add extension field fails\n%s\n",
17909c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
17919c2daa00SOllivier Robert 		rval = -1;
17929c2daa00SOllivier Robert 		return (0);
17939c2daa00SOllivier Robert 	}
17949c2daa00SOllivier Robert 	X509_EXTENSION_free(ex);
17959c2daa00SOllivier Robert 	/*
17969c2daa00SOllivier Robert 	 * The subject_key_identifier is used for the GQ public key.
17979c2daa00SOllivier Robert 	 * This should not be controversial.
17989c2daa00SOllivier Robert 	 */
17999c2daa00SOllivier Robert 	if (gqpub != NULL) {
18009c2daa00SOllivier Robert 		fprintf(stderr, "%s\n", LN_subject_key_identifier);
18019c2daa00SOllivier Robert 		ex = X509V3_EXT_conf_nid(NULL, NULL,
18029c2daa00SOllivier Robert 		    NID_subject_key_identifier, gqpub);
18039c2daa00SOllivier Robert 		if (!X509_add_ext(cert, ex, -1)) {
18049c2daa00SOllivier Robert 			fprintf(stderr,
18059c2daa00SOllivier Robert 			    "Add extension field fails\n%s\n",
18069c2daa00SOllivier Robert 			    ERR_error_string(ERR_get_error(), NULL));
18079c2daa00SOllivier Robert 			rval = -1;
18089c2daa00SOllivier Robert 			return (0);
18099c2daa00SOllivier Robert 		}
18109c2daa00SOllivier Robert 		X509_EXTENSION_free(ex);
18119c2daa00SOllivier Robert 	}
18129c2daa00SOllivier Robert 
18139c2daa00SOllivier Robert 	/*
18149c2daa00SOllivier Robert 	 * The extended key usage extension is used for special purpose
18159c2daa00SOllivier Robert 	 * here. The semantics probably do not conform to the designer's
18169c2daa00SOllivier Robert 	 * intent and will likely change in future.
18179c2daa00SOllivier Robert 	 *
18189c2daa00SOllivier Robert 	 * "trustRoot" designates a root authority
18199c2daa00SOllivier Robert 	 * "private" designates a private certificate
18209c2daa00SOllivier Robert 	 */
18219c2daa00SOllivier Robert 	if (exten != NULL) {
18229c2daa00SOllivier Robert 		fprintf(stderr, "%s: %s\n", LN_ext_key_usage, exten);
18239c2daa00SOllivier Robert 		ex = X509V3_EXT_conf_nid(NULL, NULL,
18249c2daa00SOllivier Robert 		    NID_ext_key_usage, exten);
18259c2daa00SOllivier Robert 		if (!X509_add_ext(cert, ex, -1)) {
18269c2daa00SOllivier Robert 			fprintf(stderr,
18279c2daa00SOllivier Robert 			    "Add extension field fails\n%s\n",
18289c2daa00SOllivier Robert 			    ERR_error_string(ERR_get_error(), NULL));
18299c2daa00SOllivier Robert 			rval = -1;
18309c2daa00SOllivier Robert 			return (0);
18319c2daa00SOllivier Robert 		}
18329c2daa00SOllivier Robert 		X509_EXTENSION_free(ex);
18339c2daa00SOllivier Robert 	}
18349c2daa00SOllivier Robert 
18359c2daa00SOllivier Robert 	/*
18369c2daa00SOllivier Robert 	 * Sign and verify.
18379c2daa00SOllivier Robert 	 */
18389c2daa00SOllivier Robert 	X509_sign(cert, pkey, md);
18399c2daa00SOllivier Robert 	if (!X509_verify(cert, pkey)) {
18409c2daa00SOllivier Robert 		fprintf(stderr, "Verify %s certificate fails\n%s\n", id,
18419c2daa00SOllivier Robert 		    ERR_error_string(ERR_get_error(), NULL));
18429c2daa00SOllivier Robert 		X509_free(cert);
18439c2daa00SOllivier Robert 		rval = -1;
18449c2daa00SOllivier Robert 		return (0);
18459c2daa00SOllivier Robert 	}
18469c2daa00SOllivier Robert 
18479c2daa00SOllivier Robert 	/*
18489c2daa00SOllivier Robert 	 * Write the certificate encoded in PEM.
18499c2daa00SOllivier Robert 	 */
18509c2daa00SOllivier Robert 	sprintf(pathbuf, "%scert", id);
18519c2daa00SOllivier Robert 	str = fheader(pathbuf, hostname);
18529c2daa00SOllivier Robert 	PEM_write_X509(str, cert);
18539c2daa00SOllivier Robert 	fclose(str);
18549c2daa00SOllivier Robert 	if (debug)
18559c2daa00SOllivier Robert 		X509_print_fp(stdout, cert);
18569c2daa00SOllivier Robert 	X509_free(cert);
18579c2daa00SOllivier Robert 	fslink("cert", hostname);
18589c2daa00SOllivier Robert 	return (1);
18599c2daa00SOllivier Robert }
18609c2daa00SOllivier Robert 
18619c2daa00SOllivier Robert #if 0	/* asn2ntp is not used */
18629c2daa00SOllivier Robert /*
18639c2daa00SOllivier Robert  * asn2ntp - convert ASN1_TIME time structure to NTP time
18649c2daa00SOllivier Robert  */
18659c2daa00SOllivier Robert u_long
18669c2daa00SOllivier Robert asn2ntp	(
18679c2daa00SOllivier Robert 	ASN1_TIME *asn1time	/* pointer to ASN1_TIME structure */
18689c2daa00SOllivier Robert 	)
18699c2daa00SOllivier Robert {
18709c2daa00SOllivier Robert 	char	*v;		/* pointer to ASN1_TIME string */
18719c2daa00SOllivier Robert 	struct	tm tm;		/* time decode structure time */
18729c2daa00SOllivier Robert 
18739c2daa00SOllivier Robert 	/*
18749c2daa00SOllivier Robert 	 * Extract time string YYMMDDHHMMSSZ from ASN.1 time structure.
18759c2daa00SOllivier Robert 	 * Note that the YY, MM, DD fields start with one, the HH, MM,
18769c2daa00SOllivier Robert 	 * SS fiels start with zero and the Z character should be 'Z'
18779c2daa00SOllivier Robert 	 * for UTC. Also note that years less than 50 map to years
18789c2daa00SOllivier Robert 	 * greater than 100. Dontcha love ASN.1?
18799c2daa00SOllivier Robert 	 */
18809c2daa00SOllivier Robert 	if (asn1time->length > 13)
18819c2daa00SOllivier Robert 		return (-1);
18829c2daa00SOllivier Robert 	v = (char *)asn1time->data;
18839c2daa00SOllivier Robert 	tm.tm_year = (v[0] - '0') * 10 + v[1] - '0';
18849c2daa00SOllivier Robert 	if (tm.tm_year < 50)
18859c2daa00SOllivier Robert 		tm.tm_year += 100;
18869c2daa00SOllivier Robert 	tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1;
18879c2daa00SOllivier Robert 	tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0';
18889c2daa00SOllivier Robert 	tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0';
18899c2daa00SOllivier Robert 	tm.tm_min = (v[8] - '0') * 10 + v[9] - '0';
18909c2daa00SOllivier Robert 	tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0';
18919c2daa00SOllivier Robert 	tm.tm_wday = 0;
18929c2daa00SOllivier Robert 	tm.tm_yday = 0;
18939c2daa00SOllivier Robert 	tm.tm_isdst = 0;
18949c2daa00SOllivier Robert 	return (mktime(&tm) + JAN_1970);
18959c2daa00SOllivier Robert }
18969c2daa00SOllivier Robert #endif
18979c2daa00SOllivier Robert 
18989c2daa00SOllivier Robert /*
18999c2daa00SOllivier Robert  * Callback routine
19009c2daa00SOllivier Robert  */
19019c2daa00SOllivier Robert void
19029c2daa00SOllivier Robert cb	(
19039c2daa00SOllivier Robert 	int	n1,		/* arg 1 */
19049c2daa00SOllivier Robert 	int	n2,		/* arg 2 */
19059c2daa00SOllivier Robert 	void	*chr		/* arg 3 */
19069c2daa00SOllivier Robert 	)
19079c2daa00SOllivier Robert {
19089c2daa00SOllivier Robert 	switch (n1) {
19099c2daa00SOllivier Robert 	case 0:
19109c2daa00SOllivier Robert 		d0++;
19119c2daa00SOllivier Robert 		fprintf(stderr, "%s %d %d %lu\r", (char *)chr, n1, n2,
19129c2daa00SOllivier Robert 		    d0);
19139c2daa00SOllivier Robert 		break;
19149c2daa00SOllivier Robert 	case 1:
19159c2daa00SOllivier Robert 		d1++;
19169c2daa00SOllivier Robert 		fprintf(stderr, "%s\t\t%d %d %lu\r", (char *)chr, n1,
19179c2daa00SOllivier Robert 		    n2, d1);
19189c2daa00SOllivier Robert 		break;
19199c2daa00SOllivier Robert 	case 2:
19209c2daa00SOllivier Robert 		d2++;
19219c2daa00SOllivier Robert 		fprintf(stderr, "%s\t\t\t\t%d %d %lu\r", (char *)chr,
19229c2daa00SOllivier Robert 		    n1, n2, d2);
19239c2daa00SOllivier Robert 		break;
19249c2daa00SOllivier Robert 	case 3:
19259c2daa00SOllivier Robert 		d3++;
19269c2daa00SOllivier Robert 		fprintf(stderr, "%s\t\t\t\t\t\t%d %d %lu\r",
19279c2daa00SOllivier Robert 		    (char *)chr, n1, n2, d3);
19289c2daa00SOllivier Robert 		break;
19299c2daa00SOllivier Robert 	}
19309c2daa00SOllivier Robert }
19319c2daa00SOllivier Robert 
19329c2daa00SOllivier Robert 
19339c2daa00SOllivier Robert /*
19349c2daa00SOllivier Robert  * Generate key
19359c2daa00SOllivier Robert  */
19369c2daa00SOllivier Robert EVP_PKEY *			/* public/private key pair */
19379c2daa00SOllivier Robert genkey(
19389c2daa00SOllivier Robert 	char	*type,		/* key type (RSA or DSA) */
19399c2daa00SOllivier Robert 	char	*id		/* file name id */
19409c2daa00SOllivier Robert 	)
19419c2daa00SOllivier Robert {
19429c2daa00SOllivier Robert 	if (type == NULL)
19439c2daa00SOllivier Robert 		return (NULL);
19449c2daa00SOllivier Robert 	if (strcmp(type, "RSA") == 0)
19459c2daa00SOllivier Robert 		return (gen_rsa(id));
19469c2daa00SOllivier Robert 
19479c2daa00SOllivier Robert 	else if (strcmp(type, "DSA") == 0)
19489c2daa00SOllivier Robert 		return (gen_dsa(id));
19499c2daa00SOllivier Robert 
19509c2daa00SOllivier Robert 	fprintf(stderr, "Invalid %s key type %s\n", id, type);
19519c2daa00SOllivier Robert 	rval = -1;
19529c2daa00SOllivier Robert 	return (NULL);
19539c2daa00SOllivier Robert }
19545e91a9b7SOllivier Robert #endif /* OPENSSL */
19559c2daa00SOllivier Robert 
19569c2daa00SOllivier Robert 
19579c2daa00SOllivier Robert /*
19589c2daa00SOllivier Robert  * Generate file header
19599c2daa00SOllivier Robert  */
19609c2daa00SOllivier Robert FILE *
19619c2daa00SOllivier Robert fheader	(
19629c2daa00SOllivier Robert 	const char *id,		/* file name id */
19639c2daa00SOllivier Robert 	const char *name	/* owner name */
19649c2daa00SOllivier Robert 	)
19659c2daa00SOllivier Robert {
19669c2daa00SOllivier Robert 	FILE	*str;		/* file handle */
19679c2daa00SOllivier Robert 
19689c2daa00SOllivier Robert 	sprintf(filename, "ntpkey_%s_%s.%lu", id, name, epoch +
19699c2daa00SOllivier Robert 	    JAN_1970);
19709c2daa00SOllivier Robert 	if ((str = fopen(filename, "w")) == NULL) {
19719c2daa00SOllivier Robert 		perror("Write");
19729c2daa00SOllivier Robert 		exit (-1);
19739c2daa00SOllivier Robert 	}
19749c2daa00SOllivier Robert 	fprintf(str, "# %s\n# %s", filename, ctime(&epoch));
19759c2daa00SOllivier Robert 	return (str);
19769c2daa00SOllivier Robert }
19779c2daa00SOllivier Robert 
19789c2daa00SOllivier Robert 
19799c2daa00SOllivier Robert /*
19809c2daa00SOllivier Robert  * Generate symbolic links
19819c2daa00SOllivier Robert  */
19829c2daa00SOllivier Robert void
19839c2daa00SOllivier Robert fslink(
19849c2daa00SOllivier Robert 	const char *id,		/* file name id */
19859c2daa00SOllivier Robert 	const char *name	/* owner name */
19869c2daa00SOllivier Robert 	)
19879c2daa00SOllivier Robert {
19889c2daa00SOllivier Robert 	char	linkname[MAXFILENAME]; /* link name */
19899c2daa00SOllivier Robert 	int	temp;
19909c2daa00SOllivier Robert 
19919c2daa00SOllivier Robert 	sprintf(linkname, "ntpkey_%s_%s", id, name);
19929c2daa00SOllivier Robert 	remove(linkname);
19939c2daa00SOllivier Robert 	temp = symlink(filename, linkname);
19949c2daa00SOllivier Robert 	if (temp < 0)
19959c2daa00SOllivier Robert 		perror(id);
19969c2daa00SOllivier Robert 	fprintf(stderr, "Generating new %s file and link\n", id);
19979c2daa00SOllivier Robert 	fprintf(stderr, "%s->%s\n", linkname, filename);
19989c2daa00SOllivier Robert }
1999