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