19c2daa00SOllivier Robert /* 22b15cb3dSCy Schubert * Program to generate cryptographic keys for ntp clients and servers 39c2daa00SOllivier Robert * 42b15cb3dSCy Schubert * This program generates password encrypted data files for use with the 52b15cb3dSCy Schubert * Autokey security protocol and Network Time Protocol Version 4. Files 62b15cb3dSCy Schubert * are prefixed with a header giving the name and date of creation 79c2daa00SOllivier Robert * followed by a type-specific descriptive label and PEM-encoded data 82b15cb3dSCy Schubert * structure compatible with programs of the OpenSSL library. 99c2daa00SOllivier Robert * 102b15cb3dSCy Schubert * All file names are like "ntpkey_<type>_<hostname>.<filestamp>", where 112b15cb3dSCy Schubert * <type> is the file type, <hostname> the generating host name and 122b15cb3dSCy Schubert * <filestamp> the generation time in NTP seconds. The NTP programs 132b15cb3dSCy Schubert * expect generic names such as "ntpkey_<type>_whimsy.udel.edu" with the 142b15cb3dSCy Schubert * association maintained by soft links. Following is a list of file 152b15cb3dSCy Schubert * types; the first line is the file name and the second link name. 169c2daa00SOllivier Robert * 179c2daa00SOllivier Robert * ntpkey_MD5key_<hostname>.<filestamp> 189c2daa00SOllivier Robert * MD5 (128-bit) keys used to compute message digests in symmetric 199c2daa00SOllivier Robert * key cryptography 209c2daa00SOllivier Robert * 212b15cb3dSCy Schubert * ntpkey_RSAhost_<hostname>.<filestamp> 222b15cb3dSCy Schubert * ntpkey_host_<hostname> 239c2daa00SOllivier Robert * RSA private/public host key pair used for public key signatures 249c2daa00SOllivier Robert * 252b15cb3dSCy Schubert * ntpkey_RSAsign_<hostname>.<filestamp> 262b15cb3dSCy Schubert * ntpkey_sign_<hostname> 272b15cb3dSCy Schubert * RSA private/public sign key pair used for public key signatures 289c2daa00SOllivier Robert * 292b15cb3dSCy Schubert * ntpkey_DSAsign_<hostname>.<filestamp> 302b15cb3dSCy Schubert * ntpkey_sign_<hostname> 312b15cb3dSCy Schubert * DSA Private/public sign key pair used for public key signatures 329c2daa00SOllivier Robert * 339c2daa00SOllivier Robert * Available digest/signature schemes 349c2daa00SOllivier Robert * 359c2daa00SOllivier Robert * RSA: RSA-MD2, RSA-MD5, RSA-SHA, RSA-SHA1, RSA-MDC2, EVP-RIPEMD160 369c2daa00SOllivier Robert * DSA: DSA-SHA, DSA-SHA1 379c2daa00SOllivier Robert * 382b15cb3dSCy Schubert * ntpkey_XXXcert_<hostname>.<filestamp> 392b15cb3dSCy Schubert * ntpkey_cert_<hostname> 402b15cb3dSCy Schubert * X509v3 certificate using RSA or DSA public keys and signatures. 412b15cb3dSCy Schubert * XXX is a code identifying the message digest and signature 422b15cb3dSCy Schubert * encryption algorithm 432b15cb3dSCy Schubert * 442b15cb3dSCy Schubert * Identity schemes. The key type par is used for the challenge; the key 452b15cb3dSCy Schubert * type key is used for the response. 462b15cb3dSCy Schubert * 472b15cb3dSCy Schubert * ntpkey_IFFkey_<groupname>.<filestamp> 482b15cb3dSCy Schubert * ntpkey_iffkey_<groupname> 492b15cb3dSCy Schubert * Schnorr (IFF) identity parameters and keys 502b15cb3dSCy Schubert * 512b15cb3dSCy Schubert * ntpkey_GQkey_<groupname>.<filestamp>, 522b15cb3dSCy Schubert * ntpkey_gqkey_<groupname> 532b15cb3dSCy Schubert * Guillou-Quisquater (GQ) identity parameters and keys 542b15cb3dSCy Schubert * 552b15cb3dSCy Schubert * ntpkey_MVkeyX_<groupname>.<filestamp>, 562b15cb3dSCy Schubert * ntpkey_mvkey_<groupname> 572b15cb3dSCy Schubert * Mu-Varadharajan (MV) identity parameters and keys 582b15cb3dSCy Schubert * 599c2daa00SOllivier Robert * Note: Once in a while because of some statistical fluke this program 609c2daa00SOllivier Robert * fails to generate and verify some cryptographic data, as indicated by 619c2daa00SOllivier Robert * exit status -1. In this case simply run the program again. If the 622b15cb3dSCy Schubert * program does complete with exit code 0, the data are correct as 639c2daa00SOllivier Robert * verified. 649c2daa00SOllivier Robert * 659c2daa00SOllivier Robert * These cryptographic routines are characterized by the prime modulus 669c2daa00SOllivier Robert * size in bits. The default value of 512 bits is a compromise between 679c2daa00SOllivier Robert * cryptographic strength and computing time and is ordinarily 689c2daa00SOllivier Robert * considered adequate for this application. The routines have been 699c2daa00SOllivier Robert * tested with sizes of 256, 512, 1024 and 2048 bits. Not all message 709c2daa00SOllivier Robert * digest and signature encryption schemes work with sizes less than 512 719c2daa00SOllivier Robert * bits. The computing time for sizes greater than 2048 bits is 729c2daa00SOllivier Robert * prohibitive on all but the fastest processors. An UltraSPARC Blade 739c2daa00SOllivier Robert * 1000 took something over nine minutes to generate and verify the 749c2daa00SOllivier Robert * values with size 2048. An old SPARC IPC would take a week. 759c2daa00SOllivier Robert * 769c2daa00SOllivier Robert * The OpenSSL library used by this program expects a random seed file. 779c2daa00SOllivier Robert * As described in the OpenSSL documentation, the file name defaults to 789c2daa00SOllivier Robert * first the RANDFILE environment variable in the user's home directory 799c2daa00SOllivier Robert * and then .rnd in the user's home directory. 809c2daa00SOllivier Robert */ 819c2daa00SOllivier Robert #ifdef HAVE_CONFIG_H 829c2daa00SOllivier Robert # include <config.h> 839c2daa00SOllivier Robert #endif 849c2daa00SOllivier Robert #include <string.h> 859c2daa00SOllivier Robert #include <stdio.h> 869c2daa00SOllivier Robert #include <stdlib.h> 879c2daa00SOllivier Robert #include <unistd.h> 889c2daa00SOllivier Robert #include <sys/stat.h> 899c2daa00SOllivier Robert #include <sys/time.h> 909c2daa00SOllivier Robert #include <sys/types.h> 912b15cb3dSCy Schubert 922b15cb3dSCy Schubert #include "ntp.h" 93ea906c41SOllivier Robert #include "ntp_random.h" 942b15cb3dSCy Schubert #include "ntp_stdlib.h" 952b15cb3dSCy Schubert #include "ntp_assert.h" 962b15cb3dSCy Schubert #include "ntp_libopts.h" 972b15cb3dSCy Schubert #include "ntp_unixtime.h" 98ea906c41SOllivier Robert #include "ntp-keygen-opts.h" 99ea906c41SOllivier Robert 1009c2daa00SOllivier Robert #ifdef OPENSSL 101*f0574f5cSXin LI #include "openssl/asn1.h" 1029c2daa00SOllivier Robert #include "openssl/bn.h" 103*f0574f5cSXin LI #include "openssl/crypto.h" 1049c2daa00SOllivier Robert #include "openssl/evp.h" 1059c2daa00SOllivier Robert #include "openssl/err.h" 1069c2daa00SOllivier Robert #include "openssl/rand.h" 107*f0574f5cSXin LI #include "openssl/opensslv.h" 1089c2daa00SOllivier Robert #include "openssl/pem.h" 109*f0574f5cSXin LI #include "openssl/x509.h" 1109c2daa00SOllivier Robert #include "openssl/x509v3.h" 1119c2daa00SOllivier Robert #include <openssl/objects.h> 112f391d6bcSXin LI #include "libssl_compat.h" 1139c2daa00SOllivier Robert #endif /* OPENSSL */ 1142b15cb3dSCy Schubert #include <ssl_applink.c> 1159c2daa00SOllivier Robert 1162b15cb3dSCy Schubert #define _UC(str) ((char *)(intptr_t)(str)) 1179c2daa00SOllivier Robert /* 1189c2daa00SOllivier Robert * Cryptodefines 1199c2daa00SOllivier Robert */ 1202b15cb3dSCy Schubert #define MD5KEYS 10 /* number of keys generated of each type */ 1212b15cb3dSCy Schubert #define MD5SIZE 20 /* maximum key size */ 1222b15cb3dSCy Schubert #ifdef AUTOKEY 1239c2daa00SOllivier Robert #define PLEN 512 /* default prime modulus size (bits) */ 1242b15cb3dSCy Schubert #define ILEN 256 /* default identity modulus size (bits) */ 1252b15cb3dSCy Schubert #define MVMAX 100 /* max MV parameters */ 1269c2daa00SOllivier Robert 1279c2daa00SOllivier Robert /* 1289c2daa00SOllivier Robert * Strings used in X509v3 extension fields 1299c2daa00SOllivier Robert */ 1309c2daa00SOllivier Robert #define KEY_USAGE "digitalSignature,keyCertSign" 1319c2daa00SOllivier Robert #define BASIC_CONSTRAINTS "critical,CA:TRUE" 1329c2daa00SOllivier Robert #define EXT_KEY_PRIVATE "private" 1339c2daa00SOllivier Robert #define EXT_KEY_TRUST "trustRoot" 1342b15cb3dSCy Schubert #endif /* AUTOKEY */ 1359c2daa00SOllivier Robert 1369c2daa00SOllivier Robert /* 1379c2daa00SOllivier Robert * Prototypes 1389c2daa00SOllivier Robert */ 1392b15cb3dSCy Schubert FILE *fheader (const char *, const char *, const char *); 1402b15cb3dSCy Schubert int gen_md5 (const char *); 1412b15cb3dSCy Schubert void followlink (char *, size_t); 1422b15cb3dSCy Schubert #ifdef AUTOKEY 1432b15cb3dSCy Schubert EVP_PKEY *gen_rsa (const char *); 1442b15cb3dSCy Schubert EVP_PKEY *gen_dsa (const char *); 1452b15cb3dSCy Schubert EVP_PKEY *gen_iffkey (const char *); 1462b15cb3dSCy Schubert EVP_PKEY *gen_gqkey (const char *); 1472b15cb3dSCy Schubert EVP_PKEY *gen_mvkey (const char *, EVP_PKEY **); 1482b15cb3dSCy Schubert void gen_mvserv (char *, EVP_PKEY **); 1492b15cb3dSCy Schubert int x509 (EVP_PKEY *, const EVP_MD *, char *, const char *, 1502b15cb3dSCy Schubert char *); 1512b15cb3dSCy Schubert void cb (int, int, void *); 1522b15cb3dSCy Schubert EVP_PKEY *genkey (const char *, const char *); 1532b15cb3dSCy Schubert EVP_PKEY *readkey (char *, char *, u_int *, EVP_PKEY **); 1542b15cb3dSCy Schubert void writekey (char *, char *, u_int *, EVP_PKEY **); 1552b15cb3dSCy Schubert u_long asn2ntp (ASN1_TIME *); 156f391d6bcSXin LI 157f391d6bcSXin LI static DSA* genDsaParams(int, char*); 158f391d6bcSXin LI static RSA* genRsaKeyPair(int, char*); 159f391d6bcSXin LI 1602b15cb3dSCy Schubert #endif /* AUTOKEY */ 1619c2daa00SOllivier Robert 1629c2daa00SOllivier Robert /* 1639c2daa00SOllivier Robert * Program variables 1649c2daa00SOllivier Robert */ 1659c2daa00SOllivier Robert extern char *optarg; /* command line argument */ 1669034852cSGleb Smirnoff char const *progname; 1672b15cb3dSCy Schubert u_int lifetime = DAYSPERYEAR; /* certificate lifetime (days) */ 1682b15cb3dSCy Schubert int nkeys; /* MV keys */ 1699c2daa00SOllivier Robert time_t epoch; /* Unix epoch (seconds) since 1970 */ 1702b15cb3dSCy Schubert u_int fstamp; /* NTP filestamp */ 1712b15cb3dSCy Schubert char hostbuf[MAXHOSTNAME + 1]; 1722b15cb3dSCy Schubert char *hostname = NULL; /* host, used in cert filenames */ 1732b15cb3dSCy Schubert char *groupname = NULL; /* group name */ 1742b15cb3dSCy Schubert char certnamebuf[2 * sizeof(hostbuf)]; 1752b15cb3dSCy Schubert char *certname = NULL; /* certificate subject/issuer name */ 1769c2daa00SOllivier Robert char *passwd1 = NULL; /* input private key password */ 1779c2daa00SOllivier Robert char *passwd2 = NULL; /* output private key password */ 1782b15cb3dSCy Schubert char filename[MAXFILENAME + 1]; /* file name */ 1792b15cb3dSCy Schubert #ifdef AUTOKEY 1802b15cb3dSCy Schubert u_int modulus = PLEN; /* prime modulus size (bits) */ 1812b15cb3dSCy Schubert u_int modulus2 = ILEN; /* identity modulus size (bits) */ 1829c2daa00SOllivier Robert long d0, d1, d2, d3; /* callback counters */ 1832b15cb3dSCy Schubert const EVP_CIPHER * cipher = NULL; 1842b15cb3dSCy Schubert #endif /* AUTOKEY */ 1859c2daa00SOllivier Robert 1869c2daa00SOllivier Robert #ifdef SYS_WINNT 1879c2daa00SOllivier Robert BOOL init_randfile(); 1889c2daa00SOllivier Robert 1899c2daa00SOllivier Robert /* 1902b15cb3dSCy Schubert * Don't try to follow symbolic links on Windows. Assume link == file. 1919c2daa00SOllivier Robert */ 1929c2daa00SOllivier Robert int 1932b15cb3dSCy Schubert readlink( 1942b15cb3dSCy Schubert char * link, 1952b15cb3dSCy Schubert char * file, 1962b15cb3dSCy Schubert int len 1972b15cb3dSCy Schubert ) 1982b15cb3dSCy Schubert { 1993311ff84SXin LI return (int)strlen(file); /* assume no overflow possible */ 2009c2daa00SOllivier Robert } 2012b15cb3dSCy Schubert 2029c2daa00SOllivier Robert /* 2032b15cb3dSCy Schubert * Don't try to create symbolic links on Windows, that is supported on 2042b15cb3dSCy Schubert * Vista and later only. Instead, if CreateHardLink is available (XP 2052b15cb3dSCy Schubert * and later), hardlink the linkname to the original filename. On 2062b15cb3dSCy Schubert * earlier systems, user must rename file to match expected link for 2072b15cb3dSCy Schubert * ntpd to find it. To allow building a ntp-keygen.exe which loads on 2082b15cb3dSCy Schubert * Windows pre-XP, runtime link to CreateHardLinkA(). 2099c2daa00SOllivier Robert */ 2109c2daa00SOllivier Robert int 2112b15cb3dSCy Schubert symlink( 2122b15cb3dSCy Schubert char * filename, 2132b15cb3dSCy Schubert char* linkname 2142b15cb3dSCy Schubert ) 2152b15cb3dSCy Schubert { 2162b15cb3dSCy Schubert typedef BOOL (WINAPI *PCREATEHARDLINKA)( 2172b15cb3dSCy Schubert __in LPCSTR lpFileName, 2182b15cb3dSCy Schubert __in LPCSTR lpExistingFileName, 2192b15cb3dSCy Schubert __reserved LPSECURITY_ATTRIBUTES lpSA 2202b15cb3dSCy Schubert ); 2212b15cb3dSCy Schubert static PCREATEHARDLINKA pCreateHardLinkA; 2222b15cb3dSCy Schubert static int tried; 2232b15cb3dSCy Schubert HMODULE hDll; 2242b15cb3dSCy Schubert FARPROC pfn; 2252b15cb3dSCy Schubert int link_created; 2262b15cb3dSCy Schubert int saved_errno; 2272b15cb3dSCy Schubert 2282b15cb3dSCy Schubert if (!tried) { 2292b15cb3dSCy Schubert tried = TRUE; 2302b15cb3dSCy Schubert hDll = LoadLibrary("kernel32"); 2312b15cb3dSCy Schubert pfn = GetProcAddress(hDll, "CreateHardLinkA"); 2322b15cb3dSCy Schubert pCreateHardLinkA = (PCREATEHARDLINKA)pfn; 2339c2daa00SOllivier Robert } 2342b15cb3dSCy Schubert 2352b15cb3dSCy Schubert if (NULL == pCreateHardLinkA) { 2362b15cb3dSCy Schubert errno = ENOSYS; 2372b15cb3dSCy Schubert return -1; 2382b15cb3dSCy Schubert } 2392b15cb3dSCy Schubert 2402b15cb3dSCy Schubert link_created = (*pCreateHardLinkA)(linkname, filename, NULL); 2412b15cb3dSCy Schubert 2422b15cb3dSCy Schubert if (link_created) 2432b15cb3dSCy Schubert return 0; 2442b15cb3dSCy Schubert 2452b15cb3dSCy Schubert saved_errno = GetLastError(); /* yes we play loose */ 2462b15cb3dSCy Schubert mfprintf(stderr, "Create hard link %s to %s failed: %m\n", 2472b15cb3dSCy Schubert linkname, filename); 2482b15cb3dSCy Schubert errno = saved_errno; 2492b15cb3dSCy Schubert return -1; 2502b15cb3dSCy Schubert } 2512b15cb3dSCy Schubert 2529c2daa00SOllivier Robert void 2539c2daa00SOllivier Robert InitWin32Sockets() { 2549c2daa00SOllivier Robert WORD wVersionRequested; 2559c2daa00SOllivier Robert WSADATA wsaData; 2569c2daa00SOllivier Robert wVersionRequested = MAKEWORD(2,0); 2579c2daa00SOllivier Robert if (WSAStartup(wVersionRequested, &wsaData)) 2589c2daa00SOllivier Robert { 2592b15cb3dSCy Schubert fprintf(stderr, "No useable winsock.dll\n"); 2609c2daa00SOllivier Robert exit(1); 2619c2daa00SOllivier Robert } 2629c2daa00SOllivier Robert } 2639c2daa00SOllivier Robert #endif /* SYS_WINNT */ 2649c2daa00SOllivier Robert 2652b15cb3dSCy Schubert 2662b15cb3dSCy Schubert /* 2672b15cb3dSCy Schubert * followlink() - replace filename with its target if symlink. 2682b15cb3dSCy Schubert * 2692b15cb3dSCy Schubert * Some readlink() implementations do not null-terminate the result. 2702b15cb3dSCy Schubert */ 2712b15cb3dSCy Schubert void 2722b15cb3dSCy Schubert followlink( 2732b15cb3dSCy Schubert char * fname, 2742b15cb3dSCy Schubert size_t bufsiz 2752b15cb3dSCy Schubert ) 2762b15cb3dSCy Schubert { 2772b15cb3dSCy Schubert int len; 2782b15cb3dSCy Schubert 2792b15cb3dSCy Schubert REQUIRE(bufsiz > 0); 2802b15cb3dSCy Schubert 2812b15cb3dSCy Schubert len = readlink(fname, fname, (int)bufsiz); 2822b15cb3dSCy Schubert if (len < 0 ) { 2832b15cb3dSCy Schubert fname[0] = '\0'; 2842b15cb3dSCy Schubert return; 2852b15cb3dSCy Schubert } 2862b15cb3dSCy Schubert if (len > (int)bufsiz - 1) 2872b15cb3dSCy Schubert len = (int)bufsiz - 1; 2882b15cb3dSCy Schubert fname[len] = '\0'; 2892b15cb3dSCy Schubert } 2902b15cb3dSCy Schubert 2912b15cb3dSCy Schubert 2929c2daa00SOllivier Robert /* 2939c2daa00SOllivier Robert * Main program 2949c2daa00SOllivier Robert */ 2959c2daa00SOllivier Robert int 2969c2daa00SOllivier Robert main( 2979c2daa00SOllivier Robert int argc, /* command line options */ 2989c2daa00SOllivier Robert char **argv 2999c2daa00SOllivier Robert ) 3009c2daa00SOllivier Robert { 3019c2daa00SOllivier Robert struct timeval tv; /* initialization vector */ 302ea906c41SOllivier Robert int md5key = 0; /* generate MD5 keys */ 3032b15cb3dSCy Schubert int optct; /* option count */ 3042b15cb3dSCy Schubert #ifdef AUTOKEY 3059c2daa00SOllivier Robert X509 *cert = NULL; /* X509 certificate */ 3069c2daa00SOllivier Robert EVP_PKEY *pkey_host = NULL; /* host key */ 3079c2daa00SOllivier Robert EVP_PKEY *pkey_sign = NULL; /* sign key */ 3082b15cb3dSCy Schubert EVP_PKEY *pkey_iffkey = NULL; /* IFF sever keys */ 3092b15cb3dSCy Schubert EVP_PKEY *pkey_gqkey = NULL; /* GQ server keys */ 3102b15cb3dSCy Schubert EVP_PKEY *pkey_mvkey = NULL; /* MV trusted agen keys */ 3112b15cb3dSCy Schubert EVP_PKEY *pkey_mvpar[MVMAX]; /* MV cleient keys */ 3129c2daa00SOllivier Robert int hostkey = 0; /* generate RSA keys */ 3132b15cb3dSCy Schubert int iffkey = 0; /* generate IFF keys */ 3142b15cb3dSCy Schubert int gqkey = 0; /* generate GQ keys */ 3159c2daa00SOllivier Robert int mvkey = 0; /* update MV keys */ 3162b15cb3dSCy Schubert int mvpar = 0; /* generate MV parameters */ 3179c2daa00SOllivier Robert char *sign = NULL; /* sign key */ 3189c2daa00SOllivier Robert EVP_PKEY *pkey = NULL; /* temp key */ 3199c2daa00SOllivier Robert const EVP_MD *ectx; /* EVP digest */ 3209c2daa00SOllivier Robert char pathbuf[MAXFILENAME + 1]; 3219c2daa00SOllivier Robert const char *scheme = NULL; /* digest/signature scheme */ 3222b15cb3dSCy Schubert const char *ciphername = NULL; /* to encrypt priv. key */ 3232b15cb3dSCy Schubert const char *exten = NULL; /* private extension */ 3249c2daa00SOllivier Robert char *grpkey = NULL; /* identity extension */ 3259c2daa00SOllivier Robert int nid; /* X509 digest/signature scheme */ 3269c2daa00SOllivier Robert FILE *fstr = NULL; /* file handle */ 3272b15cb3dSCy Schubert char groupbuf[MAXHOSTNAME + 1]; 328ea906c41SOllivier Robert u_int temp; 3292b15cb3dSCy Schubert BIO * bp; 3302b15cb3dSCy Schubert int i, cnt; 3312b15cb3dSCy Schubert char * ptr; 3322b15cb3dSCy Schubert #endif /* AUTOKEY */ 333*f0574f5cSXin LI #ifdef OPENSSL 334*f0574f5cSXin LI const char *sslvtext; 335*f0574f5cSXin LI int sslvmatch; 336*f0574f5cSXin LI #endif /* OPENSSL */ 3372b15cb3dSCy Schubert 3382b15cb3dSCy Schubert progname = argv[0]; 3399c2daa00SOllivier Robert 3409c2daa00SOllivier Robert #ifdef SYS_WINNT 3419c2daa00SOllivier Robert /* Initialize before OpenSSL checks */ 3429c2daa00SOllivier Robert InitWin32Sockets(); 3439c2daa00SOllivier Robert if (!init_randfile()) 3449c2daa00SOllivier Robert fprintf(stderr, "Unable to initialize .rnd file\n"); 3452b15cb3dSCy Schubert ssl_applink(); 3469c2daa00SOllivier Robert #endif 3479c2daa00SOllivier Robert 3489c2daa00SOllivier Robert #ifdef OPENSSL 3492b15cb3dSCy Schubert ssl_check_version(); 3509c2daa00SOllivier Robert #endif /* OPENSSL */ 3519c2daa00SOllivier Robert 3522b15cb3dSCy Schubert ntp_crypto_srandom(); 3532b15cb3dSCy Schubert 3549c2daa00SOllivier Robert /* 3559c2daa00SOllivier Robert * Process options, initialize host name and timestamp. 3562b15cb3dSCy Schubert * gethostname() won't null-terminate if hostname is exactly the 3572b15cb3dSCy Schubert * length provided for the buffer. 3589c2daa00SOllivier Robert */ 3592b15cb3dSCy Schubert gethostname(hostbuf, sizeof(hostbuf) - 1); 3602b15cb3dSCy Schubert hostbuf[COUNTOF(hostbuf) - 1] = '\0'; 3619c2daa00SOllivier Robert hostname = hostbuf; 3622b15cb3dSCy Schubert groupname = hostbuf; 3639c2daa00SOllivier Robert passwd1 = hostbuf; 3642b15cb3dSCy Schubert passwd2 = NULL; 3652b15cb3dSCy Schubert GETTIMEOFDAY(&tv, NULL); 3669c2daa00SOllivier Robert epoch = tv.tv_sec; 3672b15cb3dSCy Schubert fstamp = (u_int)(epoch + JAN_1970); 368ea906c41SOllivier Robert 3692b15cb3dSCy Schubert optct = ntpOptionProcess(&ntp_keygenOptions, argc, argv); 3709034852cSGleb Smirnoff argc -= optct; // Just in case we care later. 3719034852cSGleb Smirnoff argv += optct; // Just in case we care later. 3729c2daa00SOllivier Robert 3735e91a9b7SOllivier Robert #ifdef OPENSSL 374*f0574f5cSXin LI sslvtext = OpenSSL_version(OPENSSL_VERSION); 375*f0574f5cSXin LI sslvmatch = OpenSSL_version_num() == OPENSSL_VERSION_NUMBER; 376*f0574f5cSXin LI if (sslvmatch) 3772b15cb3dSCy Schubert fprintf(stderr, "Using OpenSSL version %s\n", 378*f0574f5cSXin LI sslvtext); 3792b15cb3dSCy Schubert else 3802b15cb3dSCy Schubert fprintf(stderr, "Built against OpenSSL %s, using version %s\n", 381*f0574f5cSXin LI OPENSSL_VERSION_TEXT, sslvtext); 3822b15cb3dSCy Schubert #endif /* OPENSSL */ 3839c2daa00SOllivier Robert 3842b15cb3dSCy Schubert debug = OPT_VALUE_SET_DEBUG_LEVEL; 3859c2daa00SOllivier Robert 3862b15cb3dSCy Schubert if (HAVE_OPT( MD5KEY )) 3872b15cb3dSCy Schubert md5key++; 3882b15cb3dSCy Schubert #ifdef AUTOKEY 3892b15cb3dSCy Schubert if (HAVE_OPT( PASSWORD )) 3902b15cb3dSCy Schubert passwd1 = estrdup(OPT_ARG( PASSWORD )); 3919c2daa00SOllivier Robert 3922b15cb3dSCy Schubert if (HAVE_OPT( EXPORT_PASSWD )) 3932b15cb3dSCy Schubert passwd2 = estrdup(OPT_ARG( EXPORT_PASSWD )); 3949c2daa00SOllivier Robert 395ea906c41SOllivier Robert if (HAVE_OPT( HOST_KEY )) 3969c2daa00SOllivier Robert hostkey++; 3979c2daa00SOllivier Robert 3982b15cb3dSCy Schubert if (HAVE_OPT( SIGN_KEY )) 3992b15cb3dSCy Schubert sign = estrdup(OPT_ARG( SIGN_KEY )); 4002b15cb3dSCy Schubert 4012b15cb3dSCy Schubert if (HAVE_OPT( GQ_PARAMS )) 4022b15cb3dSCy Schubert gqkey++; 4032b15cb3dSCy Schubert 404ea906c41SOllivier Robert if (HAVE_OPT( IFFKEY )) 4059c2daa00SOllivier Robert iffkey++; 406ea906c41SOllivier Robert 4072b15cb3dSCy Schubert if (HAVE_OPT( MV_PARAMS )) { 4082b15cb3dSCy Schubert mvkey++; 4092b15cb3dSCy Schubert nkeys = OPT_VALUE_MV_PARAMS; 4102b15cb3dSCy Schubert } 4112b15cb3dSCy Schubert if (HAVE_OPT( MV_KEYS )) { 4122b15cb3dSCy Schubert mvpar++; 4132b15cb3dSCy Schubert nkeys = OPT_VALUE_MV_KEYS; 4142b15cb3dSCy Schubert } 4159c2daa00SOllivier Robert 4162b15cb3dSCy Schubert if (HAVE_OPT( IMBITS )) 4172b15cb3dSCy Schubert modulus2 = OPT_VALUE_IMBITS; 4189c2daa00SOllivier Robert 419ea906c41SOllivier Robert if (HAVE_OPT( MODULUS )) 420ea906c41SOllivier Robert modulus = OPT_VALUE_MODULUS; 4219c2daa00SOllivier Robert 4222b15cb3dSCy Schubert if (HAVE_OPT( CERTIFICATE )) 4232b15cb3dSCy Schubert scheme = OPT_ARG( CERTIFICATE ); 4242b15cb3dSCy Schubert 4252b15cb3dSCy Schubert if (HAVE_OPT( CIPHER )) 4262b15cb3dSCy Schubert ciphername = OPT_ARG( CIPHER ); 4272b15cb3dSCy Schubert 4282b15cb3dSCy Schubert if (HAVE_OPT( SUBJECT_NAME )) 4292b15cb3dSCy Schubert hostname = estrdup(OPT_ARG( SUBJECT_NAME )); 4302b15cb3dSCy Schubert 4312b15cb3dSCy Schubert if (HAVE_OPT( IDENT )) 4322b15cb3dSCy Schubert groupname = estrdup(OPT_ARG( IDENT )); 4332b15cb3dSCy Schubert 4342b15cb3dSCy Schubert if (HAVE_OPT( LIFETIME )) 4352b15cb3dSCy Schubert lifetime = OPT_VALUE_LIFETIME; 4362b15cb3dSCy Schubert 437ea906c41SOllivier Robert if (HAVE_OPT( PVT_CERT )) 4389c2daa00SOllivier Robert exten = EXT_KEY_PRIVATE; 4399c2daa00SOllivier Robert 440ea906c41SOllivier Robert if (HAVE_OPT( TRUSTED_CERT )) 4419c2daa00SOllivier Robert exten = EXT_KEY_TRUST; 4429c2daa00SOllivier Robert 4432b15cb3dSCy Schubert /* 4442b15cb3dSCy Schubert * Remove the group name from the hostname variable used 4452b15cb3dSCy Schubert * in host and sign certificate file names. 4462b15cb3dSCy Schubert */ 4472b15cb3dSCy Schubert if (hostname != hostbuf) 4482b15cb3dSCy Schubert ptr = strchr(hostname, '@'); 4492b15cb3dSCy Schubert else 4502b15cb3dSCy Schubert ptr = NULL; 4512b15cb3dSCy Schubert if (ptr != NULL) { 4522b15cb3dSCy Schubert *ptr = '\0'; 4532b15cb3dSCy Schubert groupname = estrdup(ptr + 1); 4542b15cb3dSCy Schubert /* -s @group is equivalent to -i group, host unch. */ 4552b15cb3dSCy Schubert if (ptr == hostname) 4562b15cb3dSCy Schubert hostname = hostbuf; 457ea906c41SOllivier Robert } 4589c2daa00SOllivier Robert 4592b15cb3dSCy Schubert /* 4602b15cb3dSCy Schubert * Derive host certificate issuer/subject names from host name 4612b15cb3dSCy Schubert * and optional group. If no groupname is provided, the issuer 4622b15cb3dSCy Schubert * and subject is the hostname with no '@group', and the 4632b15cb3dSCy Schubert * groupname variable is pointed to hostname for use in IFF, GQ, 4642b15cb3dSCy Schubert * and MV parameters file names. 4652b15cb3dSCy Schubert */ 4662b15cb3dSCy Schubert if (groupname == hostbuf) { 4672b15cb3dSCy Schubert certname = hostname; 4682b15cb3dSCy Schubert } else { 4692b15cb3dSCy Schubert snprintf(certnamebuf, sizeof(certnamebuf), "%s@%s", 4702b15cb3dSCy Schubert hostname, groupname); 4712b15cb3dSCy Schubert certname = certnamebuf; 472ea906c41SOllivier Robert } 4739c2daa00SOllivier Robert 4749c2daa00SOllivier Robert /* 4759c2daa00SOllivier Robert * Seed random number generator and grow weeds. 4769c2daa00SOllivier Robert */ 477*f0574f5cSXin LI #if OPENSSL_VERSION_NUMBER < 0x10100000L 4789c2daa00SOllivier Robert ERR_load_crypto_strings(); 4799c2daa00SOllivier Robert OpenSSL_add_all_algorithms(); 480*f0574f5cSXin LI #endif /* OPENSSL_VERSION_NUMBER */ 4812b15cb3dSCy Schubert if (!RAND_status()) { 4822b15cb3dSCy Schubert if (RAND_file_name(pathbuf, sizeof(pathbuf)) == NULL) { 4839c2daa00SOllivier Robert fprintf(stderr, "RAND_file_name %s\n", 4849c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 4852b15cb3dSCy Schubert exit (-1); 4869c2daa00SOllivier Robert } 4879c2daa00SOllivier Robert temp = RAND_load_file(pathbuf, -1); 4889c2daa00SOllivier Robert if (temp == 0) { 4899c2daa00SOllivier Robert fprintf(stderr, 4902b15cb3dSCy Schubert "RAND_load_file %s not found or empty\n", 4912b15cb3dSCy Schubert pathbuf); 4922b15cb3dSCy Schubert exit (-1); 4939c2daa00SOllivier Robert } 4949c2daa00SOllivier Robert fprintf(stderr, 4959c2daa00SOllivier Robert "Random seed file %s %u bytes\n", pathbuf, temp); 4969c2daa00SOllivier Robert RAND_add(&epoch, sizeof(epoch), 4.0); 4972b15cb3dSCy Schubert } 4982b15cb3dSCy Schubert #endif /* AUTOKEY */ 4999c2daa00SOllivier Robert 5009c2daa00SOllivier Robert /* 5012b15cb3dSCy Schubert * Create new unencrypted MD5 keys file if requested. If this 5022b15cb3dSCy Schubert * option is selected, ignore all other options. 5039c2daa00SOllivier Robert */ 5042b15cb3dSCy Schubert if (md5key) { 5052b15cb3dSCy Schubert gen_md5("md5"); 5062b15cb3dSCy Schubert exit (0); 5072b15cb3dSCy Schubert } 5089c2daa00SOllivier Robert 5092b15cb3dSCy Schubert #ifdef AUTOKEY 5109c2daa00SOllivier Robert /* 5112b15cb3dSCy Schubert * Load previous certificate if available. 5129c2daa00SOllivier Robert */ 5132b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_cert_%s", hostname); 5149c2daa00SOllivier Robert if ((fstr = fopen(filename, "r")) != NULL) { 5159c2daa00SOllivier Robert cert = PEM_read_X509(fstr, NULL, NULL, NULL); 5169c2daa00SOllivier Robert fclose(fstr); 5172b15cb3dSCy Schubert } 5182b15cb3dSCy Schubert if (cert != NULL) { 5192b15cb3dSCy Schubert 5202b15cb3dSCy Schubert /* 5212b15cb3dSCy Schubert * Extract subject name. 5222b15cb3dSCy Schubert */ 5232b15cb3dSCy Schubert X509_NAME_oneline(X509_get_subject_name(cert), groupbuf, 5242b15cb3dSCy Schubert MAXFILENAME); 5252b15cb3dSCy Schubert 5262b15cb3dSCy Schubert /* 5272b15cb3dSCy Schubert * Extract digest/signature scheme. 5282b15cb3dSCy Schubert */ 5292b15cb3dSCy Schubert if (scheme == NULL) { 530f391d6bcSXin LI nid = X509_get_signature_nid(cert); 5319c2daa00SOllivier Robert scheme = OBJ_nid2sn(nid); 5322b15cb3dSCy Schubert } 5332b15cb3dSCy Schubert 5342b15cb3dSCy Schubert /* 5352b15cb3dSCy Schubert * If a key_usage extension field is present, determine 5362b15cb3dSCy Schubert * whether this is a trusted or private certificate. 5372b15cb3dSCy Schubert */ 5382b15cb3dSCy Schubert if (exten == NULL) { 5392b15cb3dSCy Schubert ptr = strstr(groupbuf, "CN="); 5402b15cb3dSCy Schubert cnt = X509_get_ext_count(cert); 5412b15cb3dSCy Schubert for (i = 0; i < cnt; i++) { 542f391d6bcSXin LI X509_EXTENSION *ext; 543f391d6bcSXin LI ASN1_OBJECT *obj; 544f391d6bcSXin LI 5452b15cb3dSCy Schubert ext = X509_get_ext(cert, i); 546f391d6bcSXin LI obj = X509_EXTENSION_get_object(ext); 547f391d6bcSXin LI 548f391d6bcSXin LI if (OBJ_obj2nid(obj) == 5492b15cb3dSCy Schubert NID_ext_key_usage) { 5502b15cb3dSCy Schubert bp = BIO_new(BIO_s_mem()); 5512b15cb3dSCy Schubert X509V3_EXT_print(bp, ext, 0, 0); 5522b15cb3dSCy Schubert BIO_gets(bp, pathbuf, 5532b15cb3dSCy Schubert MAXFILENAME); 5542b15cb3dSCy Schubert BIO_free(bp); 5552b15cb3dSCy Schubert if (strcmp(pathbuf, 5562b15cb3dSCy Schubert "Trust Root") == 0) 5572b15cb3dSCy Schubert exten = EXT_KEY_TRUST; 5582b15cb3dSCy Schubert else if (strcmp(pathbuf, 5592b15cb3dSCy Schubert "Private") == 0) 5602b15cb3dSCy Schubert exten = EXT_KEY_PRIVATE; 5612b15cb3dSCy Schubert certname = estrdup(ptr + 3); 5629c2daa00SOllivier Robert } 5639c2daa00SOllivier Robert } 5642b15cb3dSCy Schubert } 5652b15cb3dSCy Schubert } 5662b15cb3dSCy Schubert if (scheme == NULL) 5679c2daa00SOllivier Robert scheme = "RSA-MD5"; 5682b15cb3dSCy Schubert if (ciphername == NULL) 5692b15cb3dSCy Schubert ciphername = "des-ede3-cbc"; 5702b15cb3dSCy Schubert cipher = EVP_get_cipherbyname(ciphername); 5712b15cb3dSCy Schubert if (cipher == NULL) { 5722b15cb3dSCy Schubert fprintf(stderr, "Unknown cipher %s\n", ciphername); 5732b15cb3dSCy Schubert exit(-1); 5749c2daa00SOllivier Robert } 5752b15cb3dSCy Schubert fprintf(stderr, "Using host %s group %s\n", hostname, 5762b15cb3dSCy Schubert groupname); 5772b15cb3dSCy Schubert 5782b15cb3dSCy Schubert /* 5792b15cb3dSCy Schubert * Create a new encrypted RSA host key file if requested; 5802b15cb3dSCy Schubert * otherwise, look for an existing host key file. If not found, 5812b15cb3dSCy Schubert * create a new encrypted RSA host key file. If that fails, go 5822b15cb3dSCy Schubert * no further. 5832b15cb3dSCy Schubert */ 5842b15cb3dSCy Schubert if (hostkey) 5852b15cb3dSCy Schubert pkey_host = genkey("RSA", "host"); 5862b15cb3dSCy Schubert if (pkey_host == NULL) { 5872b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_host_%s", hostname); 5882b15cb3dSCy Schubert pkey_host = readkey(filename, passwd1, &fstamp, NULL); 5892b15cb3dSCy Schubert if (pkey_host != NULL) { 5902b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 5912b15cb3dSCy Schubert fprintf(stderr, "Using host key %s\n", 5922b15cb3dSCy Schubert filename); 5932b15cb3dSCy Schubert } else { 5942b15cb3dSCy Schubert pkey_host = genkey("RSA", "host"); 5952b15cb3dSCy Schubert } 5962b15cb3dSCy Schubert } 5972b15cb3dSCy Schubert if (pkey_host == NULL) { 5982b15cb3dSCy Schubert fprintf(stderr, "Generating host key fails\n"); 5992b15cb3dSCy Schubert exit(-1); 6002b15cb3dSCy Schubert } 6012b15cb3dSCy Schubert 6022b15cb3dSCy Schubert /* 6032b15cb3dSCy Schubert * Create new encrypted RSA or DSA sign keys file if requested; 6042b15cb3dSCy Schubert * otherwise, look for an existing sign key file. If not found, 6052b15cb3dSCy Schubert * use the host key instead. 6062b15cb3dSCy Schubert */ 6072b15cb3dSCy Schubert if (sign != NULL) 6082b15cb3dSCy Schubert pkey_sign = genkey(sign, "sign"); 6092b15cb3dSCy Schubert if (pkey_sign == NULL) { 6102b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_sign_%s", 6112b15cb3dSCy Schubert hostname); 6122b15cb3dSCy Schubert pkey_sign = readkey(filename, passwd1, &fstamp, NULL); 6132b15cb3dSCy Schubert if (pkey_sign != NULL) { 6142b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 6152b15cb3dSCy Schubert fprintf(stderr, "Using sign key %s\n", 6162b15cb3dSCy Schubert filename); 6172b15cb3dSCy Schubert } else { 6182b15cb3dSCy Schubert pkey_sign = pkey_host; 6192b15cb3dSCy Schubert fprintf(stderr, "Using host key as sign key\n"); 6202b15cb3dSCy Schubert } 6212b15cb3dSCy Schubert } 6222b15cb3dSCy Schubert 6232b15cb3dSCy Schubert /* 6242b15cb3dSCy Schubert * Create new encrypted GQ server keys file if requested; 6252b15cb3dSCy Schubert * otherwise, look for an exisiting file. If found, fetch the 6262b15cb3dSCy Schubert * public key for the certificate. 6272b15cb3dSCy Schubert */ 6282b15cb3dSCy Schubert if (gqkey) 6292b15cb3dSCy Schubert pkey_gqkey = gen_gqkey("gqkey"); 6302b15cb3dSCy Schubert if (pkey_gqkey == NULL) { 6312b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_gqkey_%s", 6322b15cb3dSCy Schubert groupname); 6332b15cb3dSCy Schubert pkey_gqkey = readkey(filename, passwd1, &fstamp, NULL); 6342b15cb3dSCy Schubert if (pkey_gqkey != NULL) { 6352b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 6362b15cb3dSCy Schubert fprintf(stderr, "Using GQ parameters %s\n", 6372b15cb3dSCy Schubert filename); 6382b15cb3dSCy Schubert } 6392b15cb3dSCy Schubert } 640f391d6bcSXin LI if (pkey_gqkey != NULL) { 641f391d6bcSXin LI RSA *rsa; 642f391d6bcSXin LI const BIGNUM *q; 643f391d6bcSXin LI 644f391d6bcSXin LI rsa = EVP_PKEY_get0_RSA(pkey_gqkey); 645f391d6bcSXin LI RSA_get0_factors(rsa, NULL, &q); 646f391d6bcSXin LI grpkey = BN_bn2hex(q); 647f391d6bcSXin LI } 6482b15cb3dSCy Schubert 6492b15cb3dSCy Schubert /* 6502b15cb3dSCy Schubert * Write the nonencrypted GQ client parameters to the stdout 6512b15cb3dSCy Schubert * stream. The parameter file is the server key file with the 6522b15cb3dSCy Schubert * private key obscured. 6532b15cb3dSCy Schubert */ 6542b15cb3dSCy Schubert if (pkey_gqkey != NULL && HAVE_OPT(ID_KEY)) { 6552b15cb3dSCy Schubert RSA *rsa; 6562b15cb3dSCy Schubert 6572b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 6582b15cb3dSCy Schubert "ntpkey_gqpar_%s.%u", groupname, fstamp); 6592b15cb3dSCy Schubert fprintf(stderr, "Writing GQ parameters %s to stdout\n", 6602b15cb3dSCy Schubert filename); 6612b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 6622b15cb3dSCy Schubert ctime(&epoch)); 663f391d6bcSXin LI /* XXX: This modifies the private key and should probably use a 664f391d6bcSXin LI * copy of it instead. */ 665f391d6bcSXin LI rsa = EVP_PKEY_get0_RSA(pkey_gqkey); 666f391d6bcSXin LI RSA_set0_factors(rsa, BN_dup(BN_value_one()), BN_dup(BN_value_one())); 6672b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 6682b15cb3dSCy Schubert EVP_PKEY_assign_RSA(pkey, rsa); 6692b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 6702b15cb3dSCy Schubert NULL, NULL); 6712b15cb3dSCy Schubert fflush(stdout); 6722b15cb3dSCy Schubert if (debug) 6732b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 6742b15cb3dSCy Schubert } 6752b15cb3dSCy Schubert 6762b15cb3dSCy Schubert /* 6772b15cb3dSCy Schubert * Write the encrypted GQ server keys to the stdout stream. 6782b15cb3dSCy Schubert */ 6792b15cb3dSCy Schubert if (pkey_gqkey != NULL && passwd2 != NULL) { 6802b15cb3dSCy Schubert RSA *rsa; 6812b15cb3dSCy Schubert 6822b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 6832b15cb3dSCy Schubert "ntpkey_gqkey_%s.%u", groupname, fstamp); 6842b15cb3dSCy Schubert fprintf(stderr, "Writing GQ keys %s to stdout\n", 6852b15cb3dSCy Schubert filename); 6862b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 6872b15cb3dSCy Schubert ctime(&epoch)); 688f391d6bcSXin LI rsa = EVP_PKEY_get0_RSA(pkey_gqkey); 6892b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 6902b15cb3dSCy Schubert EVP_PKEY_assign_RSA(pkey, rsa); 6912b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 6922b15cb3dSCy Schubert NULL, passwd2); 6932b15cb3dSCy Schubert fflush(stdout); 6942b15cb3dSCy Schubert if (debug) 6952b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 6962b15cb3dSCy Schubert } 6972b15cb3dSCy Schubert 6982b15cb3dSCy Schubert /* 6992b15cb3dSCy Schubert * Create new encrypted IFF server keys file if requested; 7002b15cb3dSCy Schubert * otherwise, look for existing file. 7012b15cb3dSCy Schubert */ 7022b15cb3dSCy Schubert if (iffkey) 7032b15cb3dSCy Schubert pkey_iffkey = gen_iffkey("iffkey"); 7042b15cb3dSCy Schubert if (pkey_iffkey == NULL) { 7052b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_iffkey_%s", 7062b15cb3dSCy Schubert groupname); 7072b15cb3dSCy Schubert pkey_iffkey = readkey(filename, passwd1, &fstamp, NULL); 7082b15cb3dSCy Schubert if (pkey_iffkey != NULL) { 7092b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 7102b15cb3dSCy Schubert fprintf(stderr, "Using IFF keys %s\n", 7112b15cb3dSCy Schubert filename); 7122b15cb3dSCy Schubert } 7132b15cb3dSCy Schubert } 7142b15cb3dSCy Schubert 7152b15cb3dSCy Schubert /* 7162b15cb3dSCy Schubert * Write the nonencrypted IFF client parameters to the stdout 7172b15cb3dSCy Schubert * stream. The parameter file is the server key file with the 7182b15cb3dSCy Schubert * private key obscured. 7192b15cb3dSCy Schubert */ 7202b15cb3dSCy Schubert if (pkey_iffkey != NULL && HAVE_OPT(ID_KEY)) { 7212b15cb3dSCy Schubert DSA *dsa; 7222b15cb3dSCy Schubert 7232b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7242b15cb3dSCy Schubert "ntpkey_iffpar_%s.%u", groupname, fstamp); 7252b15cb3dSCy Schubert fprintf(stderr, "Writing IFF parameters %s to stdout\n", 7262b15cb3dSCy Schubert filename); 7272b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7282b15cb3dSCy Schubert ctime(&epoch)); 729f391d6bcSXin LI /* XXX: This modifies the private key and should probably use a 730f391d6bcSXin LI * copy of it instead. */ 731f391d6bcSXin LI dsa = EVP_PKEY_get0_DSA(pkey_iffkey); 732f391d6bcSXin LI DSA_set0_key(dsa, NULL, BN_dup(BN_value_one())); 7332b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 7342b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey, dsa); 7352b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 7362b15cb3dSCy Schubert NULL, NULL); 7372b15cb3dSCy Schubert fflush(stdout); 7382b15cb3dSCy Schubert if (debug) 7392b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 7402b15cb3dSCy Schubert } 7412b15cb3dSCy Schubert 7422b15cb3dSCy Schubert /* 7432b15cb3dSCy Schubert * Write the encrypted IFF server keys to the stdout stream. 7442b15cb3dSCy Schubert */ 7452b15cb3dSCy Schubert if (pkey_iffkey != NULL && passwd2 != NULL) { 7462b15cb3dSCy Schubert DSA *dsa; 7472b15cb3dSCy Schubert 7482b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7492b15cb3dSCy Schubert "ntpkey_iffkey_%s.%u", groupname, fstamp); 7502b15cb3dSCy Schubert fprintf(stderr, "Writing IFF keys %s to stdout\n", 7512b15cb3dSCy Schubert filename); 7522b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7532b15cb3dSCy Schubert ctime(&epoch)); 754f391d6bcSXin LI dsa = EVP_PKEY_get0_DSA(pkey_iffkey); 7552b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 7562b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey, dsa); 7572b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 7582b15cb3dSCy Schubert NULL, passwd2); 7592b15cb3dSCy Schubert fflush(stdout); 7602b15cb3dSCy Schubert if (debug) 7612b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 7622b15cb3dSCy Schubert } 7632b15cb3dSCy Schubert 7642b15cb3dSCy Schubert /* 7652b15cb3dSCy Schubert * Create new encrypted MV trusted-authority keys file if 7662b15cb3dSCy Schubert * requested; otherwise, look for existing keys file. 7672b15cb3dSCy Schubert */ 7682b15cb3dSCy Schubert if (mvkey) 7692b15cb3dSCy Schubert pkey_mvkey = gen_mvkey("mv", pkey_mvpar); 7702b15cb3dSCy Schubert if (pkey_mvkey == NULL) { 7712b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_mvta_%s", 7722b15cb3dSCy Schubert groupname); 7732b15cb3dSCy Schubert pkey_mvkey = readkey(filename, passwd1, &fstamp, 7742b15cb3dSCy Schubert pkey_mvpar); 7752b15cb3dSCy Schubert if (pkey_mvkey != NULL) { 7762b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 7772b15cb3dSCy Schubert fprintf(stderr, "Using MV keys %s\n", 7782b15cb3dSCy Schubert filename); 7792b15cb3dSCy Schubert } 7802b15cb3dSCy Schubert } 7812b15cb3dSCy Schubert 7822b15cb3dSCy Schubert /* 7832b15cb3dSCy Schubert * Write the nonencrypted MV client parameters to the stdout 7842b15cb3dSCy Schubert * stream. For the moment, we always use the client parameters 7852b15cb3dSCy Schubert * associated with client key 1. 7862b15cb3dSCy Schubert */ 7872b15cb3dSCy Schubert if (pkey_mvkey != NULL && HAVE_OPT(ID_KEY)) { 7882b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7892b15cb3dSCy Schubert "ntpkey_mvpar_%s.%u", groupname, fstamp); 7902b15cb3dSCy Schubert fprintf(stderr, "Writing MV parameters %s to stdout\n", 7912b15cb3dSCy Schubert filename); 7922b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7932b15cb3dSCy Schubert ctime(&epoch)); 7942b15cb3dSCy Schubert pkey = pkey_mvpar[2]; 7952b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 7962b15cb3dSCy Schubert NULL, NULL); 7972b15cb3dSCy Schubert fflush(stdout); 7982b15cb3dSCy Schubert if (debug) 799f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(pkey), 0); 8002b15cb3dSCy Schubert } 8012b15cb3dSCy Schubert 8022b15cb3dSCy Schubert /* 8032b15cb3dSCy Schubert * Write the encrypted MV server keys to the stdout stream. 8042b15cb3dSCy Schubert */ 8052b15cb3dSCy Schubert if (pkey_mvkey != NULL && passwd2 != NULL) { 8062b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 8072b15cb3dSCy Schubert "ntpkey_mvkey_%s.%u", groupname, fstamp); 8082b15cb3dSCy Schubert fprintf(stderr, "Writing MV keys %s to stdout\n", 8092b15cb3dSCy Schubert filename); 8102b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 8112b15cb3dSCy Schubert ctime(&epoch)); 8122b15cb3dSCy Schubert pkey = pkey_mvpar[1]; 8132b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 8142b15cb3dSCy Schubert NULL, passwd2); 8152b15cb3dSCy Schubert fflush(stdout); 8162b15cb3dSCy Schubert if (debug) 817f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(pkey), 0); 8182b15cb3dSCy Schubert } 8192b15cb3dSCy Schubert 8202b15cb3dSCy Schubert /* 8212b15cb3dSCy Schubert * Decode the digest/signature scheme and create the 8222b15cb3dSCy Schubert * certificate. Do this every time we run the program. 8232b15cb3dSCy Schubert */ 8249c2daa00SOllivier Robert ectx = EVP_get_digestbyname(scheme); 8259c2daa00SOllivier Robert if (ectx == NULL) { 8269c2daa00SOllivier Robert fprintf(stderr, 8279c2daa00SOllivier Robert "Invalid digest/signature combination %s\n", 8289c2daa00SOllivier Robert scheme); 8292b15cb3dSCy Schubert exit (-1); 8309c2daa00SOllivier Robert } 8312b15cb3dSCy Schubert x509(pkey_sign, ectx, grpkey, exten, certname); 8322b15cb3dSCy Schubert #endif /* AUTOKEY */ 8332b15cb3dSCy Schubert exit(0); 8349c2daa00SOllivier Robert } 8359c2daa00SOllivier Robert 8362b15cb3dSCy Schubert 8379c2daa00SOllivier Robert /* 8382b15cb3dSCy Schubert * Generate semi-random MD5 keys compatible with NTPv3 and NTPv4. Also, 8392b15cb3dSCy Schubert * if OpenSSL is around, generate random SHA1 keys compatible with 8402b15cb3dSCy Schubert * symmetric key cryptography. 8419c2daa00SOllivier Robert */ 8429c2daa00SOllivier Robert int 8439c2daa00SOllivier Robert gen_md5( 8442b15cb3dSCy Schubert const char *id /* file name id */ 8459c2daa00SOllivier Robert ) 8469c2daa00SOllivier Robert { 8472b15cb3dSCy Schubert u_char md5key[MD5SIZE + 1]; /* MD5 key */ 8489c2daa00SOllivier Robert FILE *str; 8499c2daa00SOllivier Robert int i, j; 8502b15cb3dSCy Schubert #ifdef OPENSSL 8512b15cb3dSCy Schubert u_char keystr[MD5SIZE]; 8522b15cb3dSCy Schubert u_char hexstr[2 * MD5SIZE + 1]; 8532b15cb3dSCy Schubert u_char hex[] = "0123456789abcdef"; 8542b15cb3dSCy Schubert #endif /* OPENSSL */ 8559c2daa00SOllivier Robert 8562b15cb3dSCy Schubert str = fheader("MD5key", id, groupname); 8579c2daa00SOllivier Robert for (i = 1; i <= MD5KEYS; i++) { 8582b15cb3dSCy Schubert for (j = 0; j < MD5SIZE; j++) { 859a25439b6SCy Schubert u_char temp; 8602b15cb3dSCy Schubert 8619c2daa00SOllivier Robert while (1) { 8622b15cb3dSCy Schubert int rc; 8632b15cb3dSCy Schubert 864a25439b6SCy Schubert rc = ntp_crypto_random_buf( 865a25439b6SCy Schubert &temp, sizeof(temp)); 8662b15cb3dSCy Schubert if (-1 == rc) { 8672b15cb3dSCy Schubert fprintf(stderr, "ntp_crypto_random_buf() failed.\n"); 8682b15cb3dSCy Schubert exit (-1); 8692b15cb3dSCy Schubert } 8709c2daa00SOllivier Robert if (temp == '#') 8719c2daa00SOllivier Robert continue; 8722b15cb3dSCy Schubert 8739c2daa00SOllivier Robert if (temp > 0x20 && temp < 0x7f) 8749c2daa00SOllivier Robert break; 8759c2daa00SOllivier Robert } 876a25439b6SCy Schubert md5key[j] = temp; 8779c2daa00SOllivier Robert } 8782b15cb3dSCy Schubert md5key[j] = '\0'; 8792b15cb3dSCy Schubert fprintf(str, "%2d MD5 %s # MD5 key\n", i, 8809c2daa00SOllivier Robert md5key); 8819c2daa00SOllivier Robert } 8822b15cb3dSCy Schubert #ifdef OPENSSL 8832b15cb3dSCy Schubert for (i = 1; i <= MD5KEYS; i++) { 8842b15cb3dSCy Schubert RAND_bytes(keystr, 20); 8852b15cb3dSCy Schubert for (j = 0; j < MD5SIZE; j++) { 8862b15cb3dSCy Schubert hexstr[2 * j] = hex[keystr[j] >> 4]; 8872b15cb3dSCy Schubert hexstr[2 * j + 1] = hex[keystr[j] & 0xf]; 8882b15cb3dSCy Schubert } 8892b15cb3dSCy Schubert hexstr[2 * MD5SIZE] = '\0'; 8902b15cb3dSCy Schubert fprintf(str, "%2d SHA1 %s # SHA1 key\n", i + MD5KEYS, 8912b15cb3dSCy Schubert hexstr); 8929c2daa00SOllivier Robert } 8939c2daa00SOllivier Robert #endif /* OPENSSL */ 8942b15cb3dSCy Schubert fclose(str); 8952b15cb3dSCy Schubert return (1); 8962b15cb3dSCy Schubert } 8979c2daa00SOllivier Robert 8989c2daa00SOllivier Robert 8992b15cb3dSCy Schubert #ifdef AUTOKEY 9002b15cb3dSCy Schubert /* 9012b15cb3dSCy Schubert * readkey - load cryptographic parameters and keys 9022b15cb3dSCy Schubert * 9032b15cb3dSCy Schubert * This routine loads a PEM-encoded file of given name and password and 9042b15cb3dSCy Schubert * extracts the filestamp from the file name. It returns a pointer to 9052b15cb3dSCy Schubert * the first key if valid, NULL if not. 9062b15cb3dSCy Schubert */ 9072b15cb3dSCy Schubert EVP_PKEY * /* public/private key pair */ 9082b15cb3dSCy Schubert readkey( 9092b15cb3dSCy Schubert char *cp, /* file name */ 9102b15cb3dSCy Schubert char *passwd, /* password */ 9112b15cb3dSCy Schubert u_int *estamp, /* file stamp */ 9122b15cb3dSCy Schubert EVP_PKEY **evpars /* parameter list pointer */ 9132b15cb3dSCy Schubert ) 9142b15cb3dSCy Schubert { 9152b15cb3dSCy Schubert FILE *str; /* file handle */ 9162b15cb3dSCy Schubert EVP_PKEY *pkey = NULL; /* public/private key */ 9172b15cb3dSCy Schubert u_int gstamp; /* filestamp */ 9182b15cb3dSCy Schubert char linkname[MAXFILENAME]; /* filestamp buffer) */ 9192b15cb3dSCy Schubert EVP_PKEY *parkey; 9202b15cb3dSCy Schubert char *ptr; 9212b15cb3dSCy Schubert int i; 9222b15cb3dSCy Schubert 9232b15cb3dSCy Schubert /* 9242b15cb3dSCy Schubert * Open the key file. 9252b15cb3dSCy Schubert */ 9262b15cb3dSCy Schubert str = fopen(cp, "r"); 9272b15cb3dSCy Schubert if (str == NULL) 9282b15cb3dSCy Schubert return (NULL); 9292b15cb3dSCy Schubert 9302b15cb3dSCy Schubert /* 9312b15cb3dSCy Schubert * Read the filestamp, which is contained in the first line. 9322b15cb3dSCy Schubert */ 9332b15cb3dSCy Schubert if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) { 9342b15cb3dSCy Schubert fprintf(stderr, "Empty key file %s\n", cp); 9352b15cb3dSCy Schubert fclose(str); 9362b15cb3dSCy Schubert return (NULL); 9372b15cb3dSCy Schubert } 9382b15cb3dSCy Schubert if ((ptr = strrchr(ptr, '.')) == NULL) { 9392b15cb3dSCy Schubert fprintf(stderr, "No filestamp found in %s\n", cp); 9402b15cb3dSCy Schubert fclose(str); 9412b15cb3dSCy Schubert return (NULL); 9422b15cb3dSCy Schubert } 9432b15cb3dSCy Schubert if (sscanf(++ptr, "%u", &gstamp) != 1) { 9442b15cb3dSCy Schubert fprintf(stderr, "Invalid filestamp found in %s\n", cp); 9452b15cb3dSCy Schubert fclose(str); 9462b15cb3dSCy Schubert return (NULL); 9472b15cb3dSCy Schubert } 9482b15cb3dSCy Schubert 9492b15cb3dSCy Schubert /* 9502b15cb3dSCy Schubert * Read and decrypt PEM-encoded private keys. The first one 9512b15cb3dSCy Schubert * found is returned. If others are expected, add them to the 9522b15cb3dSCy Schubert * parameter list. 9532b15cb3dSCy Schubert */ 9542b15cb3dSCy Schubert for (i = 0; i <= MVMAX - 1;) { 9552b15cb3dSCy Schubert parkey = PEM_read_PrivateKey(str, NULL, NULL, passwd); 9562b15cb3dSCy Schubert if (evpars != NULL) { 9572b15cb3dSCy Schubert evpars[i++] = parkey; 9582b15cb3dSCy Schubert evpars[i] = NULL; 9592b15cb3dSCy Schubert } 9602b15cb3dSCy Schubert if (parkey == NULL) 9612b15cb3dSCy Schubert break; 9622b15cb3dSCy Schubert 9632b15cb3dSCy Schubert if (pkey == NULL) 9642b15cb3dSCy Schubert pkey = parkey; 9652b15cb3dSCy Schubert if (debug) { 966f391d6bcSXin LI if (EVP_PKEY_base_id(parkey) == EVP_PKEY_DSA) 967f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(parkey), 9682b15cb3dSCy Schubert 0); 969f391d6bcSXin LI else if (EVP_PKEY_base_id(parkey) == EVP_PKEY_RSA) 970f391d6bcSXin LI RSA_print_fp(stderr, EVP_PKEY_get0_RSA(parkey), 9712b15cb3dSCy Schubert 0); 9722b15cb3dSCy Schubert } 9732b15cb3dSCy Schubert } 9742b15cb3dSCy Schubert fclose(str); 9752b15cb3dSCy Schubert if (pkey == NULL) { 9762b15cb3dSCy Schubert fprintf(stderr, "Corrupt file %s or wrong key %s\n%s\n", 9772b15cb3dSCy Schubert cp, passwd, ERR_error_string(ERR_get_error(), 9782b15cb3dSCy Schubert NULL)); 9792b15cb3dSCy Schubert exit (-1); 9802b15cb3dSCy Schubert } 9812b15cb3dSCy Schubert *estamp = gstamp; 9822b15cb3dSCy Schubert return (pkey); 9832b15cb3dSCy Schubert } 9842b15cb3dSCy Schubert 9852b15cb3dSCy Schubert 9869c2daa00SOllivier Robert /* 9879c2daa00SOllivier Robert * Generate RSA public/private key pair 9889c2daa00SOllivier Robert */ 9899c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 9909c2daa00SOllivier Robert gen_rsa( 9912b15cb3dSCy Schubert const char *id /* file name id */ 9929c2daa00SOllivier Robert ) 9939c2daa00SOllivier Robert { 9949c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 9959c2daa00SOllivier Robert RSA *rsa; /* RSA parameters and key pair */ 9969c2daa00SOllivier Robert FILE *str; 9979c2daa00SOllivier Robert 9989c2daa00SOllivier Robert fprintf(stderr, "Generating RSA keys (%d bits)...\n", modulus); 999f391d6bcSXin LI rsa = genRsaKeyPair(modulus, _UC("RSA")); 10009c2daa00SOllivier Robert fprintf(stderr, "\n"); 10019c2daa00SOllivier Robert if (rsa == NULL) { 10029c2daa00SOllivier Robert fprintf(stderr, "RSA generate keys fails\n%s\n", 10039c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10049c2daa00SOllivier Robert return (NULL); 10059c2daa00SOllivier Robert } 10069c2daa00SOllivier Robert 10079c2daa00SOllivier Robert /* 10089c2daa00SOllivier Robert * For signature encryption it is not necessary that the RSA 10099c2daa00SOllivier Robert * parameters be strictly groomed and once in a while the 10109c2daa00SOllivier Robert * modulus turns out to be non-prime. Just for grins, we check 10119c2daa00SOllivier Robert * the primality. 10129c2daa00SOllivier Robert */ 10139c2daa00SOllivier Robert if (!RSA_check_key(rsa)) { 10149c2daa00SOllivier Robert fprintf(stderr, "Invalid RSA key\n%s\n", 10159c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10169c2daa00SOllivier Robert RSA_free(rsa); 10179c2daa00SOllivier Robert return (NULL); 10189c2daa00SOllivier Robert } 10199c2daa00SOllivier Robert 10209c2daa00SOllivier Robert /* 10219c2daa00SOllivier Robert * Write the RSA parameters and keys as a RSA private key 10229c2daa00SOllivier Robert * encoded in PEM. 10239c2daa00SOllivier Robert */ 10242b15cb3dSCy Schubert if (strcmp(id, "sign") == 0) 10252b15cb3dSCy Schubert str = fheader("RSAsign", id, hostname); 10262b15cb3dSCy Schubert else 10272b15cb3dSCy Schubert str = fheader("RSAhost", id, hostname); 10289c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 10299c2daa00SOllivier Robert EVP_PKEY_assign_RSA(pkey, rsa); 10302b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 10312b15cb3dSCy Schubert passwd1); 10329c2daa00SOllivier Robert fclose(str); 10339c2daa00SOllivier Robert if (debug) 10342b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 10359c2daa00SOllivier Robert return (pkey); 10369c2daa00SOllivier Robert } 10379c2daa00SOllivier Robert 10389c2daa00SOllivier Robert 10399c2daa00SOllivier Robert /* 10409c2daa00SOllivier Robert * Generate DSA public/private key pair 10419c2daa00SOllivier Robert */ 10429c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 10439c2daa00SOllivier Robert gen_dsa( 10442b15cb3dSCy Schubert const char *id /* file name id */ 10459c2daa00SOllivier Robert ) 10469c2daa00SOllivier Robert { 10479c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 10489c2daa00SOllivier Robert DSA *dsa; /* DSA parameters */ 10499c2daa00SOllivier Robert FILE *str; 10509c2daa00SOllivier Robert 10519c2daa00SOllivier Robert /* 10529c2daa00SOllivier Robert * Generate DSA parameters. 10539c2daa00SOllivier Robert */ 10549c2daa00SOllivier Robert fprintf(stderr, 10559c2daa00SOllivier Robert "Generating DSA parameters (%d bits)...\n", modulus); 1056f391d6bcSXin LI dsa = genDsaParams(modulus, _UC("DSA")); 10579c2daa00SOllivier Robert fprintf(stderr, "\n"); 10589c2daa00SOllivier Robert if (dsa == NULL) { 10599c2daa00SOllivier Robert fprintf(stderr, "DSA generate parameters fails\n%s\n", 10609c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10619c2daa00SOllivier Robert return (NULL); 10629c2daa00SOllivier Robert } 10639c2daa00SOllivier Robert 10649c2daa00SOllivier Robert /* 10659c2daa00SOllivier Robert * Generate DSA keys. 10669c2daa00SOllivier Robert */ 10679c2daa00SOllivier Robert fprintf(stderr, "Generating DSA keys (%d bits)...\n", modulus); 10689c2daa00SOllivier Robert if (!DSA_generate_key(dsa)) { 10699c2daa00SOllivier Robert fprintf(stderr, "DSA generate keys fails\n%s\n", 10709c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10719c2daa00SOllivier Robert DSA_free(dsa); 10729c2daa00SOllivier Robert return (NULL); 10739c2daa00SOllivier Robert } 10749c2daa00SOllivier Robert 10759c2daa00SOllivier Robert /* 10769c2daa00SOllivier Robert * Write the DSA parameters and keys as a DSA private key 10779c2daa00SOllivier Robert * encoded in PEM. 10789c2daa00SOllivier Robert */ 10792b15cb3dSCy Schubert str = fheader("DSAsign", id, hostname); 10809c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 10819c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 10822b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 10832b15cb3dSCy Schubert passwd1); 10849c2daa00SOllivier Robert fclose(str); 10859c2daa00SOllivier Robert if (debug) 10862b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 10879c2daa00SOllivier Robert return (pkey); 10889c2daa00SOllivier Robert } 10899c2daa00SOllivier Robert 10909c2daa00SOllivier Robert 10919c2daa00SOllivier Robert /* 10922b15cb3dSCy Schubert *********************************************************************** 10932b15cb3dSCy Schubert * * 10942b15cb3dSCy Schubert * The following routines implement the Schnorr (IFF) identity scheme * 10952b15cb3dSCy Schubert * * 10962b15cb3dSCy Schubert *********************************************************************** 10979c2daa00SOllivier Robert * 10989c2daa00SOllivier Robert * The Schnorr (IFF) identity scheme is intended for use when 10999c2daa00SOllivier Robert * certificates are generated by some other trusted certificate 11002b15cb3dSCy Schubert * authority and the certificate cannot be used to convey public 11012b15cb3dSCy Schubert * parameters. There are two kinds of files: encrypted server files that 11022b15cb3dSCy Schubert * contain private and public values and nonencrypted client files that 11032b15cb3dSCy Schubert * contain only public values. New generations of server files must be 11042b15cb3dSCy Schubert * securely transmitted to all servers of the group; client files can be 11052b15cb3dSCy Schubert * distributed by any means. The scheme is self contained and 11062b15cb3dSCy Schubert * independent of new generations of host keys, sign keys and 11072b15cb3dSCy Schubert * certificates. 11089c2daa00SOllivier Robert * 11099c2daa00SOllivier Robert * The IFF values hide in a DSA cuckoo structure which uses the same 11109c2daa00SOllivier Robert * parameters. The values are used by an identity scheme based on DSA 11119c2daa00SOllivier Robert * cryptography and described in Stimson p. 285. The p is a 512-bit 11129c2daa00SOllivier Robert * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1 11139c2daa00SOllivier Robert * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a 11142b15cb3dSCy Schubert * private random group key b (0 < b < q) and public key v = g^b, then 11152b15cb3dSCy Schubert * sends (p, q, g, b) to the servers and (p, q, g, v) to the clients. 11162b15cb3dSCy Schubert * Alice challenges Bob to confirm identity using the protocol described 11172b15cb3dSCy Schubert * below. 11182b15cb3dSCy Schubert * 11192b15cb3dSCy Schubert * How it works 11202b15cb3dSCy Schubert * 11212b15cb3dSCy Schubert * The scheme goes like this. Both Alice and Bob have the public primes 11222b15cb3dSCy Schubert * p, q and generator g. The TA gives private key b to Bob and public 11232b15cb3dSCy Schubert * key v to Alice. 11242b15cb3dSCy Schubert * 11252b15cb3dSCy Schubert * Alice rolls new random challenge r (o < r < q) and sends to Bob in 11262b15cb3dSCy Schubert * the IFF request message. Bob rolls new random k (0 < k < q), then 11272b15cb3dSCy Schubert * computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x)) 11282b15cb3dSCy Schubert * to Alice in the response message. Besides making the response 11292b15cb3dSCy Schubert * shorter, the hash makes it effectivey impossible for an intruder to 11302b15cb3dSCy Schubert * solve for b by observing a number of these messages. 11312b15cb3dSCy Schubert * 11322b15cb3dSCy Schubert * Alice receives the response and computes g^y v^r mod p. After a bit 11332b15cb3dSCy Schubert * of algebra, this simplifies to g^k. If the hash of this result 11342b15cb3dSCy Schubert * matches hash(x), Alice knows that Bob has the group key b. The signed 11352b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 11362b15cb3dSCy Schubert * previously received in his certificate. 11372b15cb3dSCy Schubert */ 11382b15cb3dSCy Schubert /* 11392b15cb3dSCy Schubert * Generate Schnorr (IFF) keys. 11409c2daa00SOllivier Robert */ 11419c2daa00SOllivier Robert EVP_PKEY * /* DSA cuckoo nest */ 11422b15cb3dSCy Schubert gen_iffkey( 11432b15cb3dSCy Schubert const char *id /* file name id */ 11449c2daa00SOllivier Robert ) 11459c2daa00SOllivier Robert { 11469c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 11479c2daa00SOllivier Robert DSA *dsa; /* DSA parameters */ 11489c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 11499c2daa00SOllivier Robert BIGNUM *b, *r, *k, *u, *v, *w; /* BN temp */ 11509c2daa00SOllivier Robert FILE *str; 11519c2daa00SOllivier Robert u_int temp; 1152f391d6bcSXin LI const BIGNUM *p, *q, *g; 1153f391d6bcSXin LI BIGNUM *pub_key, *priv_key; 11549c2daa00SOllivier Robert 11559c2daa00SOllivier Robert /* 11569c2daa00SOllivier Robert * Generate DSA parameters for use as IFF parameters. 11579c2daa00SOllivier Robert */ 11582b15cb3dSCy Schubert fprintf(stderr, "Generating IFF keys (%d bits)...\n", 11592b15cb3dSCy Schubert modulus2); 1160f391d6bcSXin LI dsa = genDsaParams(modulus2, _UC("IFF")); 11619c2daa00SOllivier Robert fprintf(stderr, "\n"); 11629c2daa00SOllivier Robert if (dsa == NULL) { 11639c2daa00SOllivier Robert fprintf(stderr, "DSA generate parameters fails\n%s\n", 11649c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 1165f391d6bcSXin LI return (NULL); 11669c2daa00SOllivier Robert } 1167f391d6bcSXin LI DSA_get0_pqg(dsa, &p, &q, &g); 11689c2daa00SOllivier Robert 11699c2daa00SOllivier Robert /* 11709c2daa00SOllivier Robert * Generate the private and public keys. The DSA parameters and 11712b15cb3dSCy Schubert * private key are distributed to the servers, while all except 11722b15cb3dSCy Schubert * the private key are distributed to the clients. 11739c2daa00SOllivier Robert */ 11749c2daa00SOllivier Robert b = BN_new(); r = BN_new(); k = BN_new(); 11759c2daa00SOllivier Robert u = BN_new(); v = BN_new(); w = BN_new(); ctx = BN_CTX_new(); 1176f391d6bcSXin LI BN_rand(b, BN_num_bits(q), -1, 0); /* a */ 1177f391d6bcSXin LI BN_mod(b, b, q, ctx); 1178f391d6bcSXin LI BN_sub(v, q, b); 1179f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); /* g^(q - b) mod p */ 1180f391d6bcSXin LI BN_mod_exp(u, g, b, p, ctx); /* g^b mod p */ 1181f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 11829c2daa00SOllivier Robert temp = BN_is_one(u); 11839c2daa00SOllivier Robert fprintf(stderr, 11849c2daa00SOllivier Robert "Confirm g^(q - b) g^b = 1 mod p: %s\n", temp == 1 ? 11859c2daa00SOllivier Robert "yes" : "no"); 11869c2daa00SOllivier Robert if (!temp) { 11879c2daa00SOllivier Robert BN_free(b); BN_free(r); BN_free(k); 11889c2daa00SOllivier Robert BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 11899c2daa00SOllivier Robert return (NULL); 11909c2daa00SOllivier Robert } 1191f391d6bcSXin LI pub_key = BN_dup(v); 1192f391d6bcSXin LI priv_key = BN_dup(b); 1193f391d6bcSXin LI DSA_set0_key(dsa, pub_key, priv_key); 11949c2daa00SOllivier Robert 11959c2daa00SOllivier Robert /* 11969c2daa00SOllivier Robert * Here is a trial round of the protocol. First, Alice rolls 11972b15cb3dSCy Schubert * random nonce r mod q and sends it to Bob. She needs only 11982b15cb3dSCy Schubert * q from parameters. 11999c2daa00SOllivier Robert */ 1200f391d6bcSXin LI BN_rand(r, BN_num_bits(q), -1, 0); /* r */ 1201f391d6bcSXin LI BN_mod(r, r, q, ctx); 12029c2daa00SOllivier Robert 12039c2daa00SOllivier Robert /* 12042b15cb3dSCy Schubert * Bob rolls random nonce k mod q, computes y = k + b r mod q 12059c2daa00SOllivier Robert * and x = g^k mod p, then sends (y, x) to Alice. He needs 12062b15cb3dSCy Schubert * p, q and b from parameters and r from Alice. 12079c2daa00SOllivier Robert */ 1208f391d6bcSXin LI BN_rand(k, BN_num_bits(q), -1, 0); /* k, 0 < k < q */ 1209f391d6bcSXin LI BN_mod(k, k, q, ctx); 1210f391d6bcSXin LI BN_mod_mul(v, priv_key, r, q, ctx); /* b r mod q */ 12119c2daa00SOllivier Robert BN_add(v, v, k); 1212f391d6bcSXin LI BN_mod(v, v, q, ctx); /* y = k + b r mod q */ 1213f391d6bcSXin LI BN_mod_exp(u, g, k, p, ctx); /* x = g^k mod p */ 12149c2daa00SOllivier Robert 12159c2daa00SOllivier Robert /* 12162b15cb3dSCy Schubert * Alice verifies x = g^y v^r to confirm that Bob has group key 12172b15cb3dSCy Schubert * b. She needs p, q, g from parameters, (y, x) from Bob and the 12182b15cb3dSCy Schubert * original r. We omit the detail here thatt only the hash of y 12192b15cb3dSCy Schubert * is sent. 12209c2daa00SOllivier Robert */ 1221f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); /* g^y mod p */ 1222f391d6bcSXin LI BN_mod_exp(w, pub_key, r, p, ctx); /* v^r */ 1223f391d6bcSXin LI BN_mod_mul(v, w, v, p, ctx); /* product mod p */ 12249c2daa00SOllivier Robert temp = BN_cmp(u, v); 12259c2daa00SOllivier Robert fprintf(stderr, 12269c2daa00SOllivier Robert "Confirm g^k = g^(k + b r) g^(q - b) r: %s\n", temp == 12279c2daa00SOllivier Robert 0 ? "yes" : "no"); 12289c2daa00SOllivier Robert BN_free(b); BN_free(r); BN_free(k); 12299c2daa00SOllivier Robert BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 12309c2daa00SOllivier Robert if (temp != 0) { 12319c2daa00SOllivier Robert DSA_free(dsa); 12329c2daa00SOllivier Robert return (NULL); 12339c2daa00SOllivier Robert } 12349c2daa00SOllivier Robert 12359c2daa00SOllivier Robert /* 12362b15cb3dSCy Schubert * Write the IFF keys as an encrypted DSA private key encoded in 12372b15cb3dSCy Schubert * PEM. 12389c2daa00SOllivier Robert * 12399c2daa00SOllivier Robert * p modulus p 12409c2daa00SOllivier Robert * q modulus q 12419c2daa00SOllivier Robert * g generator g 12429c2daa00SOllivier Robert * priv_key b 12439c2daa00SOllivier Robert * public_key v 12442b15cb3dSCy Schubert * kinv not used 12452b15cb3dSCy Schubert * r not used 12469c2daa00SOllivier Robert */ 12472b15cb3dSCy Schubert str = fheader("IFFkey", id, groupname); 12489c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 12499c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 12502b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 12512b15cb3dSCy Schubert passwd1); 12529c2daa00SOllivier Robert fclose(str); 12539c2daa00SOllivier Robert if (debug) 12542b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 12559c2daa00SOllivier Robert return (pkey); 12569c2daa00SOllivier Robert } 12579c2daa00SOllivier Robert 12589c2daa00SOllivier Robert 12599c2daa00SOllivier Robert /* 12602b15cb3dSCy Schubert *********************************************************************** 12612b15cb3dSCy Schubert * * 12622b15cb3dSCy Schubert * The following routines implement the Guillou-Quisquater (GQ) * 12632b15cb3dSCy Schubert * identity scheme * 12642b15cb3dSCy Schubert * * 12652b15cb3dSCy Schubert *********************************************************************** 12669c2daa00SOllivier Robert * 12679c2daa00SOllivier Robert * The Guillou-Quisquater (GQ) identity scheme is intended for use when 12682b15cb3dSCy Schubert * the certificate can be used to convey public parameters. The scheme 12692b15cb3dSCy Schubert * uses a X509v3 certificate extension field do convey the public key of 12702b15cb3dSCy Schubert * a private key known only to servers. There are two kinds of files: 12712b15cb3dSCy Schubert * encrypted server files that contain private and public values and 12722b15cb3dSCy Schubert * nonencrypted client files that contain only public values. New 12732b15cb3dSCy Schubert * generations of server files must be securely transmitted to all 12742b15cb3dSCy Schubert * servers of the group; client files can be distributed by any means. 12752b15cb3dSCy Schubert * The scheme is self contained and independent of new generations of 12762b15cb3dSCy Schubert * host keys and sign keys. The scheme is self contained and independent 12772b15cb3dSCy Schubert * of new generations of host keys and sign keys. 12789c2daa00SOllivier Robert * 12799c2daa00SOllivier Robert * The GQ parameters hide in a RSA cuckoo structure which uses the same 12809c2daa00SOllivier Robert * parameters. The values are used by an identity scheme based on RSA 12819c2daa00SOllivier Robert * cryptography and described in Stimson p. 300 (with errors). The 512- 12829c2daa00SOllivier Robert * bit public modulus is n = p q, where p and q are secret large primes. 12839c2daa00SOllivier Robert * The TA rolls private random group key b as RSA exponent. These values 12849c2daa00SOllivier Robert * are known to all group members. 12859c2daa00SOllivier Robert * 12862b15cb3dSCy Schubert * When rolling new certificates, a server recomputes the private and 12879c2daa00SOllivier Robert * public keys. The private key u is a random roll, while the public key 12889c2daa00SOllivier Robert * is the inverse obscured by the group key v = (u^-1)^b. These values 12899c2daa00SOllivier Robert * replace the private and public keys normally generated by the RSA 12909c2daa00SOllivier Robert * scheme. Alice challenges Bob to confirm identity using the protocol 12919c2daa00SOllivier Robert * described below. 12929c2daa00SOllivier Robert * 12932b15cb3dSCy Schubert * How it works 12942b15cb3dSCy Schubert * 12952b15cb3dSCy Schubert * The scheme goes like this. Both Alice and Bob have the same modulus n 12962b15cb3dSCy Schubert * and some random b as the group key. These values are computed and 12972b15cb3dSCy Schubert * distributed in advance via secret means, although only the group key 12982b15cb3dSCy Schubert * b is truly secret. Each has a private random private key u and public 12992b15cb3dSCy Schubert * key (u^-1)^b, although not necessarily the same ones. Bob and Alice 13002b15cb3dSCy Schubert * can regenerate the key pair from time to time without affecting 13012b15cb3dSCy Schubert * operations. The public key is conveyed on the certificate in an 13022b15cb3dSCy Schubert * extension field; the private key is never revealed. 13032b15cb3dSCy Schubert * 13042b15cb3dSCy Schubert * Alice rolls new random challenge r and sends to Bob in the GQ 13052b15cb3dSCy Schubert * request message. Bob rolls new random k, then computes y = k u^r mod 13062b15cb3dSCy Schubert * n and x = k^b mod n and sends (y, hash(x)) to Alice in the response 13072b15cb3dSCy Schubert * message. Besides making the response shorter, the hash makes it 13082b15cb3dSCy Schubert * effectivey impossible for an intruder to solve for b by observing 13092b15cb3dSCy Schubert * a number of these messages. 13102b15cb3dSCy Schubert * 13112b15cb3dSCy Schubert * Alice receives the response and computes y^b v^r mod n. After a bit 13122b15cb3dSCy Schubert * of algebra, this simplifies to k^b. If the hash of this result 13132b15cb3dSCy Schubert * matches hash(x), Alice knows that Bob has the group key b. The signed 13142b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 13152b15cb3dSCy Schubert * previously received in his certificate. 13169c2daa00SOllivier Robert */ 13179c2daa00SOllivier Robert /* 13182b15cb3dSCy Schubert * Generate Guillou-Quisquater (GQ) parameters file. 13199c2daa00SOllivier Robert */ 13209c2daa00SOllivier Robert EVP_PKEY * /* RSA cuckoo nest */ 13219c2daa00SOllivier Robert gen_gqkey( 13222b15cb3dSCy Schubert const char *id /* file name id */ 13239c2daa00SOllivier Robert ) 13249c2daa00SOllivier Robert { 13259c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 13269c2daa00SOllivier Robert RSA *rsa; /* RSA parameters */ 13279c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 13289c2daa00SOllivier Robert BIGNUM *u, *v, *g, *k, *r, *y; /* BN temps */ 13299c2daa00SOllivier Robert FILE *str; 13309c2daa00SOllivier Robert u_int temp; 1331f391d6bcSXin LI BIGNUM *b; 1332f391d6bcSXin LI const BIGNUM *n; 13339c2daa00SOllivier Robert 13349c2daa00SOllivier Robert /* 13352b15cb3dSCy Schubert * Generate RSA parameters for use as GQ parameters. 13369c2daa00SOllivier Robert */ 13372b15cb3dSCy Schubert fprintf(stderr, 13382b15cb3dSCy Schubert "Generating GQ parameters (%d bits)...\n", 13392b15cb3dSCy Schubert modulus2); 1340f391d6bcSXin LI rsa = genRsaKeyPair(modulus2, _UC("GQ")); 13412b15cb3dSCy Schubert fprintf(stderr, "\n"); 13422b15cb3dSCy Schubert if (rsa == NULL) { 13432b15cb3dSCy Schubert fprintf(stderr, "RSA generate keys fails\n%s\n", 13442b15cb3dSCy Schubert ERR_error_string(ERR_get_error(), NULL)); 13452b15cb3dSCy Schubert return (NULL); 13462b15cb3dSCy Schubert } 1347f391d6bcSXin LI RSA_get0_key(rsa, &n, NULL, NULL); 13482b15cb3dSCy Schubert u = BN_new(); v = BN_new(); g = BN_new(); 13492b15cb3dSCy Schubert k = BN_new(); r = BN_new(); y = BN_new(); 1350f391d6bcSXin LI b = BN_new(); 13512b15cb3dSCy Schubert 13522b15cb3dSCy Schubert /* 13532b15cb3dSCy Schubert * Generate the group key b, which is saved in the e member of 13542b15cb3dSCy Schubert * the RSA structure. The group key is transmitted to each group 13552b15cb3dSCy Schubert * member encrypted by the member private key. 13562b15cb3dSCy Schubert */ 13572b15cb3dSCy Schubert ctx = BN_CTX_new(); 1358f391d6bcSXin LI BN_rand(b, BN_num_bits(n), -1, 0); /* b */ 1359f391d6bcSXin LI BN_mod(b, b, n, ctx); 13609c2daa00SOllivier Robert 13619c2daa00SOllivier Robert /* 13629c2daa00SOllivier Robert * When generating his certificate, Bob rolls random private key 13632b15cb3dSCy Schubert * u, then computes inverse v = u^-1. 13649c2daa00SOllivier Robert */ 1365f391d6bcSXin LI BN_rand(u, BN_num_bits(n), -1, 0); /* u */ 1366f391d6bcSXin LI BN_mod(u, u, n, ctx); 1367f391d6bcSXin LI BN_mod_inverse(v, u, n, ctx); /* u^-1 mod n */ 1368f391d6bcSXin LI BN_mod_mul(k, v, u, n, ctx); 13699c2daa00SOllivier Robert 13709c2daa00SOllivier Robert /* 13719c2daa00SOllivier Robert * Bob computes public key v = (u^-1)^b, which is saved in an 13729c2daa00SOllivier Robert * extension field on his certificate. We check that u^b v = 13739c2daa00SOllivier Robert * 1 mod n. 13749c2daa00SOllivier Robert */ 1375f391d6bcSXin LI BN_mod_exp(v, v, b, n, ctx); 1376f391d6bcSXin LI BN_mod_exp(g, u, b, n, ctx); /* u^b */ 1377f391d6bcSXin LI BN_mod_mul(g, g, v, n, ctx); /* u^b (u^-1)^b */ 13789c2daa00SOllivier Robert temp = BN_is_one(g); 13799c2daa00SOllivier Robert fprintf(stderr, 13809c2daa00SOllivier Robert "Confirm u^b (u^-1)^b = 1 mod n: %s\n", temp ? "yes" : 13819c2daa00SOllivier Robert "no"); 13829c2daa00SOllivier Robert if (!temp) { 13839c2daa00SOllivier Robert BN_free(u); BN_free(v); 13849c2daa00SOllivier Robert BN_free(g); BN_free(k); BN_free(r); BN_free(y); 13859c2daa00SOllivier Robert BN_CTX_free(ctx); 13869c2daa00SOllivier Robert RSA_free(rsa); 13879c2daa00SOllivier Robert return (NULL); 13889c2daa00SOllivier Robert } 1389f391d6bcSXin LI /* setting 'u' and 'v' into a RSA object takes over ownership. 1390f391d6bcSXin LI * Since we use these values again, we have to pass in dupes, 1391f391d6bcSXin LI * or we'll corrupt the program! 1392f391d6bcSXin LI */ 1393f391d6bcSXin LI RSA_set0_factors(rsa, BN_dup(u), BN_dup(v)); 13949c2daa00SOllivier Robert 13959c2daa00SOllivier Robert /* 13969c2daa00SOllivier Robert * Here is a trial run of the protocol. First, Alice rolls 13972b15cb3dSCy Schubert * random nonce r mod n and sends it to Bob. She needs only n 13982b15cb3dSCy Schubert * from parameters. 13999c2daa00SOllivier Robert */ 1400f391d6bcSXin LI BN_rand(r, BN_num_bits(n), -1, 0); /* r */ 1401f391d6bcSXin LI BN_mod(r, r, n, ctx); 14029c2daa00SOllivier Robert 14039c2daa00SOllivier Robert /* 14042b15cb3dSCy Schubert * Bob rolls random nonce k mod n, computes y = k u^r mod n and 14052b15cb3dSCy Schubert * g = k^b mod n, then sends (y, g) to Alice. He needs n, u, b 14062b15cb3dSCy Schubert * from parameters and r from Alice. 14079c2daa00SOllivier Robert */ 1408f391d6bcSXin LI BN_rand(k, BN_num_bits(n), -1, 0); /* k */ 1409f391d6bcSXin LI BN_mod(k, k, n, ctx); 1410f391d6bcSXin LI BN_mod_exp(y, u, r, n, ctx); /* u^r mod n */ 1411f391d6bcSXin LI BN_mod_mul(y, k, y, n, ctx); /* y = k u^r mod n */ 1412f391d6bcSXin LI BN_mod_exp(g, k, b, n, ctx); /* g = k^b mod n */ 14139c2daa00SOllivier Robert 14149c2daa00SOllivier Robert /* 14152b15cb3dSCy Schubert * Alice verifies g = v^r y^b mod n to confirm that Bob has 14162b15cb3dSCy Schubert * private key u. She needs n, g from parameters, public key v = 14172b15cb3dSCy Schubert * (u^-1)^b from the certificate, (y, g) from Bob and the 14182b15cb3dSCy Schubert * original r. We omit the detaul here that only the hash of g 14192b15cb3dSCy Schubert * is sent. 14209c2daa00SOllivier Robert */ 1421f391d6bcSXin LI BN_mod_exp(v, v, r, n, ctx); /* v^r mod n */ 1422f391d6bcSXin LI BN_mod_exp(y, y, b, n, ctx); /* y^b mod n */ 1423f391d6bcSXin LI BN_mod_mul(y, v, y, n, ctx); /* v^r y^b mod n */ 14249c2daa00SOllivier Robert temp = BN_cmp(y, g); 14259c2daa00SOllivier Robert fprintf(stderr, "Confirm g^k = v^r y^b mod n: %s\n", temp == 0 ? 14269c2daa00SOllivier Robert "yes" : "no"); 14279c2daa00SOllivier Robert BN_CTX_free(ctx); BN_free(u); BN_free(v); 14289c2daa00SOllivier Robert BN_free(g); BN_free(k); BN_free(r); BN_free(y); 14299c2daa00SOllivier Robert if (temp != 0) { 14309c2daa00SOllivier Robert RSA_free(rsa); 14319c2daa00SOllivier Robert return (NULL); 14329c2daa00SOllivier Robert } 14339c2daa00SOllivier Robert 14349c2daa00SOllivier Robert /* 14352b15cb3dSCy Schubert * Write the GQ parameter file as an encrypted RSA private key 14362b15cb3dSCy Schubert * encoded in PEM. 14379c2daa00SOllivier Robert * 14389c2daa00SOllivier Robert * n modulus n 14399c2daa00SOllivier Robert * e group key b 14402b15cb3dSCy Schubert * d not used 14419c2daa00SOllivier Robert * p private key u 14429c2daa00SOllivier Robert * q public key (u^-1)^b 14432b15cb3dSCy Schubert * dmp1 not used 14442b15cb3dSCy Schubert * dmq1 not used 14452b15cb3dSCy Schubert * iqmp not used 14469c2daa00SOllivier Robert */ 1447f391d6bcSXin LI RSA_set0_key(rsa, NULL, b, BN_dup(BN_value_one())); 1448f391d6bcSXin LI RSA_set0_crt_params(rsa, BN_dup(BN_value_one()), BN_dup(BN_value_one()), 1449f391d6bcSXin LI BN_dup(BN_value_one())); 14502b15cb3dSCy Schubert str = fheader("GQkey", id, groupname); 14519c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 14529c2daa00SOllivier Robert EVP_PKEY_assign_RSA(pkey, rsa); 14532b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 14542b15cb3dSCy Schubert passwd1); 14559c2daa00SOllivier Robert fclose(str); 14569c2daa00SOllivier Robert if (debug) 14572b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 14589c2daa00SOllivier Robert return (pkey); 14599c2daa00SOllivier Robert } 14609c2daa00SOllivier Robert 14619c2daa00SOllivier Robert 14629c2daa00SOllivier Robert /* 14632b15cb3dSCy Schubert *********************************************************************** 14642b15cb3dSCy Schubert * * 14652b15cb3dSCy Schubert * The following routines implement the Mu-Varadharajan (MV) identity * 14662b15cb3dSCy Schubert * scheme * 14672b15cb3dSCy Schubert * * 14682b15cb3dSCy Schubert *********************************************************************** 14699c2daa00SOllivier Robert * 14702b15cb3dSCy Schubert * The Mu-Varadharajan (MV) cryptosystem was originally intended when 14712b15cb3dSCy Schubert * servers broadcast messages to clients, but clients never send 14722b15cb3dSCy Schubert * messages to servers. There is one encryption key for the server and a 14732b15cb3dSCy Schubert * separate decryption key for each client. It operated something like a 14749c2daa00SOllivier Robert * pay-per-view satellite broadcasting system where the session key is 14759c2daa00SOllivier Robert * encrypted by the broadcaster and the decryption keys are held in a 14762b15cb3dSCy Schubert * tamperproof set-top box. 14779c2daa00SOllivier Robert * 14789c2daa00SOllivier Robert * The MV parameters and private encryption key hide in a DSA cuckoo 14799c2daa00SOllivier Robert * structure which uses the same parameters, but generated in a 14809c2daa00SOllivier Robert * different way. The values are used in an encryption scheme similar to 14819c2daa00SOllivier Robert * El Gamal cryptography and a polynomial formed from the expansion of 14829c2daa00SOllivier Robert * product terms (x - x[j]), as described in Mu, Y., and V. 14839c2daa00SOllivier Robert * Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001, 14849c2daa00SOllivier Robert * 223-231. The paper has significant errors and serious omissions. 14859c2daa00SOllivier Robert * 14862b15cb3dSCy Schubert * Let q be the product of n distinct primes s1[j] (j = 1...n), where 14872b15cb3dSCy Schubert * each s1[j] has m significant bits. Let p be a prime p = 2 * q + 1, so 14882b15cb3dSCy Schubert * that q and each s1[j] divide p - 1 and p has M = n * m + 1 14899c2daa00SOllivier Robert * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1) 14909c2daa00SOllivier Robert * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then 14919c2daa00SOllivier Robert * project into Zp* as exponents of g. Sometimes we have to compute an 14929c2daa00SOllivier Robert * inverse b^-1 of random b in Zq, but for that purpose we require 14939c2daa00SOllivier Robert * gcd(b, q) = 1. We expect M to be in the 500-bit range and n 14942b15cb3dSCy Schubert * relatively small, like 30. These are the parameters of the scheme and 14952b15cb3dSCy Schubert * they are expensive to compute. 14969c2daa00SOllivier Robert * 14979c2daa00SOllivier Robert * We set up an instance of the scheme as follows. A set of random 14989c2daa00SOllivier Robert * values x[j] mod q (j = 1...n), are generated as the zeros of a 14999c2daa00SOllivier Robert * polynomial of order n. The product terms (x - x[j]) are expanded to 15009c2daa00SOllivier Robert * form coefficients a[i] mod q (i = 0...n) in powers of x. These are 15019c2daa00SOllivier Robert * used as exponents of the generator g mod p to generate the private 15029c2daa00SOllivier Robert * encryption key A. The pair (gbar, ghat) of public server keys and the 15039c2daa00SOllivier Robert * pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used 15049c2daa00SOllivier Robert * to construct the decryption keys. The devil is in the details. 15059c2daa00SOllivier Robert * 15062b15cb3dSCy Schubert * This routine generates a private server encryption file including the 15072b15cb3dSCy Schubert * private encryption key E and partial decryption keys gbar and ghat. 15082b15cb3dSCy Schubert * It then generates public client decryption files including the public 15092b15cb3dSCy Schubert * keys xbar[j] and xhat[j] for each client j. The partial decryption 15102b15cb3dSCy Schubert * files are used to compute the inverse of E. These values are suitably 15112b15cb3dSCy Schubert * blinded so secrets are not revealed. 15129c2daa00SOllivier Robert * 15139c2daa00SOllivier Robert * The distinguishing characteristic of this scheme is the capability to 15149c2daa00SOllivier Robert * revoke keys. Included in the calculation of E, gbar and ghat is the 15152b15cb3dSCy Schubert * product s = prod(s1[j]) (j = 1...n) above. If the factor s1[j] is 15169c2daa00SOllivier Robert * subsequently removed from the product and E, gbar and ghat 15179c2daa00SOllivier Robert * recomputed, the jth client will no longer be able to compute E^-1 and 15182b15cb3dSCy Schubert * thus unable to decrypt the messageblock. 15192b15cb3dSCy Schubert * 15202b15cb3dSCy Schubert * How it works 15212b15cb3dSCy Schubert * 15222b15cb3dSCy Schubert * The scheme goes like this. Bob has the server values (p, E, q, 15232b15cb3dSCy Schubert * gbar, ghat) and Alice has the client values (p, xbar, xhat). 15242b15cb3dSCy Schubert * 15252b15cb3dSCy Schubert * Alice rolls new random nonce r mod p and sends to Bob in the MV 15262b15cb3dSCy Schubert * request message. Bob rolls random nonce k mod q, encrypts y = r E^k 15272b15cb3dSCy Schubert * mod p and sends (y, gbar^k, ghat^k) to Alice. 15282b15cb3dSCy Schubert * 15292b15cb3dSCy Schubert * Alice receives the response and computes the inverse (E^k)^-1 from 15302b15cb3dSCy Schubert * the partial decryption keys gbar^k, ghat^k, xbar and xhat. She then 15312b15cb3dSCy Schubert * decrypts y and verifies it matches the original r. The signed 15322b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 15332b15cb3dSCy Schubert * previously received in his certificate. 15349c2daa00SOllivier Robert */ 15359c2daa00SOllivier Robert EVP_PKEY * /* DSA cuckoo nest */ 15362b15cb3dSCy Schubert gen_mvkey( 15372b15cb3dSCy Schubert const char *id, /* file name id */ 15382b15cb3dSCy Schubert EVP_PKEY **evpars /* parameter list pointer */ 15399c2daa00SOllivier Robert ) 15409c2daa00SOllivier Robert { 15412b15cb3dSCy Schubert EVP_PKEY *pkey, *pkey1; /* private keys */ 15422b15cb3dSCy Schubert DSA *dsa, *dsa2, *sdsa; /* DSA parameters */ 15439c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 15442b15cb3dSCy Schubert BIGNUM *a[MVMAX]; /* polynomial coefficient vector */ 1545f391d6bcSXin LI BIGNUM *gs[MVMAX]; /* public key vector */ 15462b15cb3dSCy Schubert BIGNUM *s1[MVMAX]; /* private enabling keys */ 15472b15cb3dSCy Schubert BIGNUM *x[MVMAX]; /* polynomial zeros vector */ 15482b15cb3dSCy Schubert BIGNUM *xbar[MVMAX], *xhat[MVMAX]; /* private keys vector */ 15499c2daa00SOllivier Robert BIGNUM *b; /* group key */ 15509c2daa00SOllivier Robert BIGNUM *b1; /* inverse group key */ 15512b15cb3dSCy Schubert BIGNUM *s; /* enabling key */ 15529c2daa00SOllivier Robert BIGNUM *biga; /* master encryption key */ 15539c2daa00SOllivier Robert BIGNUM *bige; /* session encryption key */ 15549c2daa00SOllivier Robert BIGNUM *gbar, *ghat; /* public key */ 15559c2daa00SOllivier Robert BIGNUM *u, *v, *w; /* BN scratch */ 1556f391d6bcSXin LI BIGNUM *p, *q, *g, *priv_key, *pub_key; 15579c2daa00SOllivier Robert int i, j, n; 15589c2daa00SOllivier Robert FILE *str; 15599c2daa00SOllivier Robert u_int temp; 15609c2daa00SOllivier Robert 15619c2daa00SOllivier Robert /* 15629c2daa00SOllivier Robert * Generate MV parameters. 15639c2daa00SOllivier Robert * 15649c2daa00SOllivier Robert * The object is to generate a multiplicative group Zp* modulo a 15659c2daa00SOllivier Robert * prime p and a subset Zq mod q, where q is the product of n 15662b15cb3dSCy Schubert * distinct primes s1[j] (j = 1...n) and q divides p - 1. We 15672b15cb3dSCy Schubert * first generate n m-bit primes, where the product n m is in 15682b15cb3dSCy Schubert * the order of 512 bits. One or more of these may have to be 15692b15cb3dSCy Schubert * replaced later. As a practical matter, it is tough to find 15702b15cb3dSCy Schubert * more than 31 distinct primes for 512 bits or 61 primes for 15712b15cb3dSCy Schubert * 1024 bits. The latter can take several hundred iterations 15729c2daa00SOllivier Robert * and several minutes on a Sun Blade 1000. 15739c2daa00SOllivier Robert */ 15749c2daa00SOllivier Robert n = nkeys; 15759c2daa00SOllivier Robert fprintf(stderr, 15769c2daa00SOllivier Robert "Generating MV parameters for %d keys (%d bits)...\n", n, 15772b15cb3dSCy Schubert modulus2 / n); 15789c2daa00SOllivier Robert ctx = BN_CTX_new(); u = BN_new(); v = BN_new(); w = BN_new(); 15799c2daa00SOllivier Robert b = BN_new(); b1 = BN_new(); 15805e91a9b7SOllivier Robert dsa = DSA_new(); 1581f391d6bcSXin LI p = BN_new(); q = BN_new(); g = BN_new(); 1582f391d6bcSXin LI priv_key = BN_new(); pub_key = BN_new(); 15839c2daa00SOllivier Robert temp = 0; 15849c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 15852b15cb3dSCy Schubert s1[j] = BN_new(); 15869c2daa00SOllivier Robert while (1) { 1587f391d6bcSXin LI BN_generate_prime_ex(s1[j], modulus2 / n, 0, 15889c2daa00SOllivier Robert NULL, NULL, NULL); 15899c2daa00SOllivier Robert for (i = 1; i < j; i++) { 15909c2daa00SOllivier Robert if (BN_cmp(s1[i], s1[j]) == 0) 15919c2daa00SOllivier Robert break; 15929c2daa00SOllivier Robert } 15939c2daa00SOllivier Robert if (i == j) 15949c2daa00SOllivier Robert break; 15959c2daa00SOllivier Robert temp++; 15969c2daa00SOllivier Robert } 15979c2daa00SOllivier Robert } 15982b15cb3dSCy Schubert fprintf(stderr, "Birthday keys regenerated %d\n", temp); 15999c2daa00SOllivier Robert 16009c2daa00SOllivier Robert /* 16019c2daa00SOllivier Robert * Compute the modulus q as the product of the primes. Compute 16029c2daa00SOllivier Robert * the modulus p as 2 * q + 1 and test p for primality. If p 16039c2daa00SOllivier Robert * is composite, replace one of the primes with a new distinct 16049c2daa00SOllivier Robert * one and try again. Note that q will hardly be a secret since 16052b15cb3dSCy Schubert * we have to reveal p to servers, but not clients. However, 16069c2daa00SOllivier Robert * factoring q to find the primes should be adequately hard, as 16079c2daa00SOllivier Robert * this is the same problem considered hard in RSA. Question: is 16089c2daa00SOllivier Robert * it as hard to find n small prime factors totalling n bits as 16099c2daa00SOllivier Robert * it is to find two large prime factors totalling n bits? 16109c2daa00SOllivier Robert * Remember, the bad guy doesn't know n. 16119c2daa00SOllivier Robert */ 16129c2daa00SOllivier Robert temp = 0; 16139c2daa00SOllivier Robert while (1) { 1614f391d6bcSXin LI BN_one(q); 16159c2daa00SOllivier Robert for (j = 1; j <= n; j++) 1616f391d6bcSXin LI BN_mul(q, q, s1[j], ctx); 1617f391d6bcSXin LI BN_copy(p, q); 1618f391d6bcSXin LI BN_add(p, p, p); 1619f391d6bcSXin LI BN_add_word(p, 1); 1620f391d6bcSXin LI if (BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) 16219c2daa00SOllivier Robert break; 16229c2daa00SOllivier Robert 16232b15cb3dSCy Schubert temp++; 16249c2daa00SOllivier Robert j = temp % n + 1; 16259c2daa00SOllivier Robert while (1) { 1626f391d6bcSXin LI BN_generate_prime_ex(u, modulus2 / n, 0, 1627f391d6bcSXin LI NULL, NULL, NULL); 16289c2daa00SOllivier Robert for (i = 1; i <= n; i++) { 16299c2daa00SOllivier Robert if (BN_cmp(u, s1[i]) == 0) 16309c2daa00SOllivier Robert break; 16319c2daa00SOllivier Robert } 16329c2daa00SOllivier Robert if (i > n) 16339c2daa00SOllivier Robert break; 16349c2daa00SOllivier Robert } 16359c2daa00SOllivier Robert BN_copy(s1[j], u); 16369c2daa00SOllivier Robert } 16372b15cb3dSCy Schubert fprintf(stderr, "Defective keys regenerated %d\n", temp); 16389c2daa00SOllivier Robert 16399c2daa00SOllivier Robert /* 16409c2daa00SOllivier Robert * Compute the generator g using a random roll such that 16419c2daa00SOllivier Robert * gcd(g, p - 1) = 1 and g^q = 1. This is a generator of p, not 16422b15cb3dSCy Schubert * q. This may take several iterations. 16439c2daa00SOllivier Robert */ 1644f391d6bcSXin LI BN_copy(v, p); 16459c2daa00SOllivier Robert BN_sub_word(v, 1); 16469c2daa00SOllivier Robert while (1) { 1647f391d6bcSXin LI BN_rand(g, BN_num_bits(p) - 1, 0, 0); 1648f391d6bcSXin LI BN_mod(g, g, p, ctx); 1649f391d6bcSXin LI BN_gcd(u, g, v, ctx); 16509c2daa00SOllivier Robert if (!BN_is_one(u)) 16519c2daa00SOllivier Robert continue; 16529c2daa00SOllivier Robert 1653f391d6bcSXin LI BN_mod_exp(u, g, q, p, ctx); 16549c2daa00SOllivier Robert if (BN_is_one(u)) 16559c2daa00SOllivier Robert break; 16569c2daa00SOllivier Robert } 16579c2daa00SOllivier Robert 1658f391d6bcSXin LI DSA_set0_pqg(dsa, p, q, g); 1659f391d6bcSXin LI 16609c2daa00SOllivier Robert /* 16619c2daa00SOllivier Robert * Setup is now complete. Roll random polynomial roots x[j] 16622b15cb3dSCy Schubert * (j = 1...n) for all j. While it may not be strictly 16639c2daa00SOllivier Robert * necessary, Make sure each root has no factors in common with 16649c2daa00SOllivier Robert * q. 16659c2daa00SOllivier Robert */ 16669c2daa00SOllivier Robert fprintf(stderr, 16679c2daa00SOllivier Robert "Generating polynomial coefficients for %d roots (%d bits)\n", 1668f391d6bcSXin LI n, BN_num_bits(q)); 16699c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 16709c2daa00SOllivier Robert x[j] = BN_new(); 16712b15cb3dSCy Schubert 16729c2daa00SOllivier Robert while (1) { 1673f391d6bcSXin LI BN_rand(x[j], BN_num_bits(q), 0, 0); 1674f391d6bcSXin LI BN_mod(x[j], x[j], q, ctx); 1675f391d6bcSXin LI BN_gcd(u, x[j], q, ctx); 16769c2daa00SOllivier Robert if (BN_is_one(u)) 16779c2daa00SOllivier Robert break; 16789c2daa00SOllivier Robert } 16799c2daa00SOllivier Robert } 16809c2daa00SOllivier Robert 16819c2daa00SOllivier Robert /* 16829c2daa00SOllivier Robert * Generate polynomial coefficients a[i] (i = 0...n) from the 16839c2daa00SOllivier Robert * expansion of root products (x - x[j]) mod q for all j. The 16849c2daa00SOllivier Robert * method is a present from Charlie Boncelet. 16859c2daa00SOllivier Robert */ 16869c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 16879c2daa00SOllivier Robert a[i] = BN_new(); 16889c2daa00SOllivier Robert BN_one(a[i]); 16899c2daa00SOllivier Robert } 16909c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 16919c2daa00SOllivier Robert BN_zero(w); 16929c2daa00SOllivier Robert for (i = 0; i < j; i++) { 1693f391d6bcSXin LI BN_copy(u, q); 1694f391d6bcSXin LI BN_mod_mul(v, a[i], x[j], q, ctx); 16959c2daa00SOllivier Robert BN_sub(u, u, v); 16969c2daa00SOllivier Robert BN_add(u, u, w); 16979c2daa00SOllivier Robert BN_copy(w, a[i]); 1698f391d6bcSXin LI BN_mod(a[i], u, q, ctx); 16999c2daa00SOllivier Robert } 17009c2daa00SOllivier Robert } 17019c2daa00SOllivier Robert 17029c2daa00SOllivier Robert /* 1703f391d6bcSXin LI * Generate gs[i] = g^a[i] mod p for all i and the generator g. 17049c2daa00SOllivier Robert */ 17059c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 1706f391d6bcSXin LI gs[i] = BN_new(); 1707f391d6bcSXin LI BN_mod_exp(gs[i], g, a[i], p, ctx); 17089c2daa00SOllivier Robert } 17099c2daa00SOllivier Robert 17109c2daa00SOllivier Robert /* 1711f391d6bcSXin LI * Verify prod(gs[i]^(a[i] x[j]^i)) = 1 for all i, j. Note the 1712f391d6bcSXin LI * a[i] x[j]^i exponent is computed mod q, but the gs[i] is 17132b15cb3dSCy Schubert * computed mod p. also note the expression given in the paper 17142b15cb3dSCy Schubert * is incorrect. 17159c2daa00SOllivier Robert */ 17169c2daa00SOllivier Robert temp = 1; 17179c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17189c2daa00SOllivier Robert BN_one(u); 17199c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 17209c2daa00SOllivier Robert BN_set_word(v, i); 1721f391d6bcSXin LI BN_mod_exp(v, x[j], v, q, ctx); 1722f391d6bcSXin LI BN_mod_mul(v, v, a[i], q, ctx); 1723f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); 1724f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 17259c2daa00SOllivier Robert } 17269c2daa00SOllivier Robert if (!BN_is_one(u)) 17279c2daa00SOllivier Robert temp = 0; 17289c2daa00SOllivier Robert } 17299c2daa00SOllivier Robert fprintf(stderr, 1730f391d6bcSXin LI "Confirm prod(gs[i]^(x[j]^i)) = 1 for all i, j: %s\n", temp ? 17319c2daa00SOllivier Robert "yes" : "no"); 17329c2daa00SOllivier Robert if (!temp) { 17339c2daa00SOllivier Robert return (NULL); 17349c2daa00SOllivier Robert } 17359c2daa00SOllivier Robert 17369c2daa00SOllivier Robert /* 17379c2daa00SOllivier Robert * Make private encryption key A. Keep it around for awhile, 17389c2daa00SOllivier Robert * since it is expensive to compute. 17399c2daa00SOllivier Robert */ 17409c2daa00SOllivier Robert biga = BN_new(); 17412b15cb3dSCy Schubert 17429c2daa00SOllivier Robert BN_one(biga); 17439c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17449c2daa00SOllivier Robert for (i = 0; i < n; i++) { 17459c2daa00SOllivier Robert BN_set_word(v, i); 1746f391d6bcSXin LI BN_mod_exp(v, x[j], v, q, ctx); 1747f391d6bcSXin LI BN_mod_exp(v, gs[i], v, p, ctx); 1748f391d6bcSXin LI BN_mod_mul(biga, biga, v, p, ctx); 17499c2daa00SOllivier Robert } 17509c2daa00SOllivier Robert } 17519c2daa00SOllivier Robert 17529c2daa00SOllivier Robert /* 17539c2daa00SOllivier Robert * Roll private random group key b mod q (0 < b < q), where 17542b15cb3dSCy Schubert * gcd(b, q) = 1 to guarantee b^-1 exists, then compute b^-1 17559c2daa00SOllivier Robert * mod q. If b is changed, the client keys must be recomputed. 17569c2daa00SOllivier Robert */ 17579c2daa00SOllivier Robert while (1) { 1758f391d6bcSXin LI BN_rand(b, BN_num_bits(q), 0, 0); 1759f391d6bcSXin LI BN_mod(b, b, q, ctx); 1760f391d6bcSXin LI BN_gcd(u, b, q, ctx); 17619c2daa00SOllivier Robert if (BN_is_one(u)) 17629c2daa00SOllivier Robert break; 17639c2daa00SOllivier Robert } 1764f391d6bcSXin LI BN_mod_inverse(b1, b, q, ctx); 17659c2daa00SOllivier Robert 17669c2daa00SOllivier Robert /* 17679c2daa00SOllivier Robert * Make private client keys (xbar[j], xhat[j]) for all j. Note 17682b15cb3dSCy Schubert * that the keys for the jth client do not s1[j] or the product 17692b15cb3dSCy Schubert * s1[j]) (j = 1...n) which is q by construction. 17702b15cb3dSCy Schubert * 17712b15cb3dSCy Schubert * Compute the factor w such that w s1[j] = s1[j] for all j. The 17722b15cb3dSCy Schubert * easy way to do this is to compute (q + s1[j]) / s1[j]. 17732b15cb3dSCy Schubert * Exercise for the student: prove the remainder is always zero. 17749c2daa00SOllivier Robert */ 17759c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17769c2daa00SOllivier Robert xbar[j] = BN_new(); xhat[j] = BN_new(); 17772b15cb3dSCy Schubert 1778f391d6bcSXin LI BN_add(w, q, s1[j]); 17792b15cb3dSCy Schubert BN_div(w, u, w, s1[j], ctx); 17809c2daa00SOllivier Robert BN_zero(xbar[j]); 17819c2daa00SOllivier Robert BN_set_word(v, n); 17829c2daa00SOllivier Robert for (i = 1; i <= n; i++) { 17839c2daa00SOllivier Robert if (i == j) 17849c2daa00SOllivier Robert continue; 17852b15cb3dSCy Schubert 1786f391d6bcSXin LI BN_mod_exp(u, x[i], v, q, ctx); 17879c2daa00SOllivier Robert BN_add(xbar[j], xbar[j], u); 17889c2daa00SOllivier Robert } 1789f391d6bcSXin LI BN_mod_mul(xbar[j], xbar[j], b1, q, ctx); 1790f391d6bcSXin LI BN_mod_exp(xhat[j], x[j], v, q, ctx); 1791f391d6bcSXin LI BN_mod_mul(xhat[j], xhat[j], w, q, ctx); 17929c2daa00SOllivier Robert } 17939c2daa00SOllivier Robert 17949c2daa00SOllivier Robert /* 17952b15cb3dSCy Schubert * We revoke client j by dividing q by s1[j]. The quotient 17962b15cb3dSCy Schubert * becomes the enabling key s. Note we always have to revoke 17972b15cb3dSCy Schubert * one key; otherwise, the plaintext and cryptotext would be 17982b15cb3dSCy Schubert * identical. For the present there are no provisions to revoke 17992b15cb3dSCy Schubert * additional keys, so we sail on with only token revocations. 18009c2daa00SOllivier Robert */ 18012b15cb3dSCy Schubert s = BN_new(); 1802f391d6bcSXin LI BN_copy(s, q); 18032b15cb3dSCy Schubert BN_div(s, u, s, s1[n], ctx); 18049c2daa00SOllivier Robert 18059c2daa00SOllivier Robert /* 18062b15cb3dSCy Schubert * For each combination of clients to be revoked, make private 18072b15cb3dSCy Schubert * encryption key E = A^s and partial decryption keys gbar = g^s 18082b15cb3dSCy Schubert * and ghat = g^(s b), all mod p. The servers use these keys to 18092b15cb3dSCy Schubert * compute the session encryption key and partial decryption 18102b15cb3dSCy Schubert * keys. These values must be regenerated if the enabling key is 18112b15cb3dSCy Schubert * changed. 18129c2daa00SOllivier Robert */ 18139c2daa00SOllivier Robert bige = BN_new(); gbar = BN_new(); ghat = BN_new(); 1814f391d6bcSXin LI BN_mod_exp(bige, biga, s, p, ctx); 1815f391d6bcSXin LI BN_mod_exp(gbar, g, s, p, ctx); 1816f391d6bcSXin LI BN_mod_mul(v, s, b, q, ctx); 1817f391d6bcSXin LI BN_mod_exp(ghat, g, v, p, ctx); 18189c2daa00SOllivier Robert 18199c2daa00SOllivier Robert /* 18202b15cb3dSCy Schubert * Notes: We produce the key media in three steps. The first 18212b15cb3dSCy Schubert * step is to generate the system parameters p, q, g, b, A and 18222b15cb3dSCy Schubert * the enabling keys s1[j]. Associated with each s1[j] are 18232b15cb3dSCy Schubert * parameters xbar[j] and xhat[j]. All of these parameters are 18242b15cb3dSCy Schubert * retained in a data structure protecteted by the trusted-agent 18252b15cb3dSCy Schubert * password. The p, xbar[j] and xhat[j] paremeters are 18262b15cb3dSCy Schubert * distributed to the j clients. When the client keys are to be 18272b15cb3dSCy Schubert * activated, the enabled keys are multipied together to form 18282b15cb3dSCy Schubert * the master enabling key s. This and the other parameters are 18292b15cb3dSCy Schubert * used to compute the server encryption key E and the partial 18302b15cb3dSCy Schubert * decryption keys gbar and ghat. 18319c2daa00SOllivier Robert * 18322b15cb3dSCy Schubert * In the identity exchange the client rolls random r and sends 18332b15cb3dSCy Schubert * it to the server. The server rolls random k, which is used 18342b15cb3dSCy Schubert * only once, then computes the session key E^k and partial 18352b15cb3dSCy Schubert * decryption keys gbar^k and ghat^k. The server sends the 18362b15cb3dSCy Schubert * encrypted r along with gbar^k and ghat^k to the client. The 18372b15cb3dSCy Schubert * client completes the decryption and verifies it matches r. 18389c2daa00SOllivier Robert */ 18399c2daa00SOllivier Robert /* 18402b15cb3dSCy Schubert * Write the MV trusted-agent parameters and keys as a DSA 18412b15cb3dSCy Schubert * private key encoded in PEM. 18429c2daa00SOllivier Robert * 18439c2daa00SOllivier Robert * p modulus p 18442b15cb3dSCy Schubert * q modulus q 18452b15cb3dSCy Schubert * g generator g 18462b15cb3dSCy Schubert * priv_key A mod p 18472b15cb3dSCy Schubert * pub_key b mod q 18482b15cb3dSCy Schubert * (remaining values are not used) 18499c2daa00SOllivier Robert */ 18502b15cb3dSCy Schubert i = 0; 18512b15cb3dSCy Schubert str = fheader("MVta", "mvta", groupname); 18522b15cb3dSCy Schubert fprintf(stderr, "Generating MV trusted-authority keys\n"); 1853f391d6bcSXin LI BN_copy(priv_key, biga); 1854f391d6bcSXin LI BN_copy(pub_key, b); 1855f391d6bcSXin LI DSA_set0_key(dsa, pub_key, priv_key); 18569c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 18579c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 18582b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 18592b15cb3dSCy Schubert passwd1); 18602b15cb3dSCy Schubert evpars[i++] = pkey; 18619c2daa00SOllivier Robert if (debug) 18622b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 18639c2daa00SOllivier Robert 18649c2daa00SOllivier Robert /* 18652b15cb3dSCy Schubert * Append the MV server parameters and keys as a DSA key encoded 18662b15cb3dSCy Schubert * in PEM. 18672b15cb3dSCy Schubert * 18682b15cb3dSCy Schubert * p modulus p 18692b15cb3dSCy Schubert * q modulus q (used only when generating k) 18702b15cb3dSCy Schubert * g bige 18712b15cb3dSCy Schubert * priv_key gbar 18722b15cb3dSCy Schubert * pub_key ghat 18732b15cb3dSCy Schubert * (remaining values are not used) 18749c2daa00SOllivier Robert */ 18752b15cb3dSCy Schubert fprintf(stderr, "Generating MV server keys\n"); 18762b15cb3dSCy Schubert dsa2 = DSA_new(); 1877f391d6bcSXin LI DSA_set0_pqg(dsa2, BN_dup(p), BN_dup(q), BN_dup(bige)); 1878f391d6bcSXin LI DSA_set0_key(dsa2, BN_dup(ghat), BN_dup(gbar)); 18792b15cb3dSCy Schubert pkey1 = EVP_PKEY_new(); 18802b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey1, dsa2); 18812b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey1, cipher, NULL, 0, NULL, 18822b15cb3dSCy Schubert passwd1); 18832b15cb3dSCy Schubert evpars[i++] = pkey1; 18842b15cb3dSCy Schubert if (debug) 18852b15cb3dSCy Schubert DSA_print_fp(stderr, dsa2, 0); 18869c2daa00SOllivier Robert 18879c2daa00SOllivier Robert /* 18882b15cb3dSCy Schubert * Append the MV client parameters for each client j as DSA keys 18892b15cb3dSCy Schubert * encoded in PEM. 18909c2daa00SOllivier Robert * 18919c2daa00SOllivier Robert * p modulus p 18929c2daa00SOllivier Robert * priv_key xbar[j] mod q 18939c2daa00SOllivier Robert * pub_key xhat[j] mod q 18949c2daa00SOllivier Robert * (remaining values are not used) 18959c2daa00SOllivier Robert */ 18962b15cb3dSCy Schubert fprintf(stderr, "Generating %d MV client keys\n", n); 18972b15cb3dSCy Schubert for (j = 1; j <= n; j++) { 18982b15cb3dSCy Schubert sdsa = DSA_new(); 1899f391d6bcSXin LI DSA_set0_pqg(sdsa, BN_dup(p), BN_dup(BN_value_one()), 1900f391d6bcSXin LI BN_dup(BN_value_one())); 1901f391d6bcSXin LI DSA_set0_key(sdsa, BN_dup(xhat[j]), BN_dup(xbar[j])); 19025e91a9b7SOllivier Robert pkey1 = EVP_PKEY_new(); 19035e91a9b7SOllivier Robert EVP_PKEY_set1_DSA(pkey1, sdsa); 19042b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey1, cipher, NULL, 0, 19052b15cb3dSCy Schubert NULL, passwd1); 19062b15cb3dSCy Schubert evpars[i++] = pkey1; 19079c2daa00SOllivier Robert if (debug) 19082b15cb3dSCy Schubert DSA_print_fp(stderr, sdsa, 0); 19092b15cb3dSCy Schubert 19102b15cb3dSCy Schubert /* 1911f391d6bcSXin LI * The product (gbar^k)^xbar[j] (ghat^k)^xhat[j] and E 19122b15cb3dSCy Schubert * are inverses of each other. We check that the product 19132b15cb3dSCy Schubert * is one for each client except the ones that have been 19142b15cb3dSCy Schubert * revoked. 19152b15cb3dSCy Schubert */ 1916f391d6bcSXin LI BN_mod_exp(v, gbar, xhat[j], p, ctx); 1917f391d6bcSXin LI BN_mod_exp(u, ghat, xbar[j], p, ctx); 1918f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 1919f391d6bcSXin LI BN_mod_mul(u, u, bige, p, ctx); 19202b15cb3dSCy Schubert if (!BN_is_one(u)) { 19212b15cb3dSCy Schubert fprintf(stderr, "Revoke key %d\n", j); 19222b15cb3dSCy Schubert continue; 19239c2daa00SOllivier Robert } 19242b15cb3dSCy Schubert } 19252b15cb3dSCy Schubert evpars[i++] = NULL; 19262b15cb3dSCy Schubert fclose(str); 19279c2daa00SOllivier Robert 19289c2daa00SOllivier Robert /* 19299c2daa00SOllivier Robert * Free the countries. 19309c2daa00SOllivier Robert */ 19319c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 1932f391d6bcSXin LI BN_free(a[i]); BN_free(gs[i]); 19339c2daa00SOllivier Robert } 19342b15cb3dSCy Schubert for (j = 1; j <= n; j++) { 19352b15cb3dSCy Schubert BN_free(x[j]); BN_free(xbar[j]); BN_free(xhat[j]); 19362b15cb3dSCy Schubert BN_free(s1[j]); 19372b15cb3dSCy Schubert } 19389c2daa00SOllivier Robert return (pkey); 19399c2daa00SOllivier Robert } 19409c2daa00SOllivier Robert 19419c2daa00SOllivier Robert 19429c2daa00SOllivier Robert /* 19432b15cb3dSCy Schubert * Generate X509v3 certificate. 19449c2daa00SOllivier Robert * 19459c2daa00SOllivier Robert * The certificate consists of the version number, serial number, 19469c2daa00SOllivier Robert * validity interval, issuer name, subject name and public key. For a 19479c2daa00SOllivier Robert * self-signed certificate, the issuer name is the same as the subject 19489c2daa00SOllivier Robert * name and these items are signed using the subject private key. The 19499c2daa00SOllivier Robert * validity interval extends from the current time to the same time one 19509c2daa00SOllivier Robert * year hence. For NTP purposes, it is convenient to use the NTP seconds 19519c2daa00SOllivier Robert * of the current time as the serial number. 19529c2daa00SOllivier Robert */ 19539c2daa00SOllivier Robert int 19549c2daa00SOllivier Robert x509 ( 19552b15cb3dSCy Schubert EVP_PKEY *pkey, /* signing key */ 19562b15cb3dSCy Schubert const EVP_MD *md, /* signature/digest scheme */ 19579c2daa00SOllivier Robert char *gqpub, /* identity extension (hex string) */ 19582b15cb3dSCy Schubert const char *exten, /* private cert extension */ 19592b15cb3dSCy Schubert char *name /* subject/issuer name */ 19609c2daa00SOllivier Robert ) 19619c2daa00SOllivier Robert { 19629c2daa00SOllivier Robert X509 *cert; /* X509 certificate */ 19639c2daa00SOllivier Robert X509_NAME *subj; /* distinguished (common) name */ 19649c2daa00SOllivier Robert X509_EXTENSION *ex; /* X509v3 extension */ 19659c2daa00SOllivier Robert FILE *str; /* file handle */ 19669c2daa00SOllivier Robert ASN1_INTEGER *serial; /* serial number */ 19679c2daa00SOllivier Robert const char *id; /* digest/signature scheme name */ 19689c2daa00SOllivier Robert char pathbuf[MAXFILENAME + 1]; 19699c2daa00SOllivier Robert 19709c2daa00SOllivier Robert /* 19719c2daa00SOllivier Robert * Generate X509 self-signed certificate. 19729c2daa00SOllivier Robert * 19739c2daa00SOllivier Robert * Set the certificate serial to the NTP seconds for grins. Set 19742b15cb3dSCy Schubert * the version to 3. Set the initial validity to the current 19752b15cb3dSCy Schubert * time and the finalvalidity one year hence. 19769c2daa00SOllivier Robert */ 1977f391d6bcSXin LI id = OBJ_nid2sn(EVP_MD_pkey_type(md)); 19782b15cb3dSCy Schubert fprintf(stderr, "Generating new certificate %s %s\n", name, id); 19799c2daa00SOllivier Robert cert = X509_new(); 19809c2daa00SOllivier Robert X509_set_version(cert, 2L); 19819c2daa00SOllivier Robert serial = ASN1_INTEGER_new(); 19822b15cb3dSCy Schubert ASN1_INTEGER_set(serial, (long)epoch + JAN_1970); 19839c2daa00SOllivier Robert X509_set_serialNumber(cert, serial); 19849c2daa00SOllivier Robert ASN1_INTEGER_free(serial); 1985*f0574f5cSXin LI X509_time_adj(X509_getm_notBefore(cert), 0L, &epoch); 1986*f0574f5cSXin LI X509_time_adj(X509_getm_notAfter(cert), lifetime * SECSPERDAY, &epoch); 19879c2daa00SOllivier Robert subj = X509_get_subject_name(cert); 19889c2daa00SOllivier Robert X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, 19893311ff84SXin LI (u_char *)name, -1, -1, 0); 19909c2daa00SOllivier Robert subj = X509_get_issuer_name(cert); 19919c2daa00SOllivier Robert X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, 19923311ff84SXin LI (u_char *)name, -1, -1, 0); 19939c2daa00SOllivier Robert if (!X509_set_pubkey(cert, pkey)) { 19942b15cb3dSCy Schubert fprintf(stderr, "Assign certificate signing key fails\n%s\n", 19959c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 19969c2daa00SOllivier Robert X509_free(cert); 19979c2daa00SOllivier Robert return (0); 19989c2daa00SOllivier Robert } 19999c2daa00SOllivier Robert 20009c2daa00SOllivier Robert /* 20019c2daa00SOllivier Robert * Add X509v3 extensions if present. These represent the minimum 20029c2daa00SOllivier Robert * set defined in RFC3280 less the certificate_policy extension, 20039c2daa00SOllivier Robert * which is seriously obfuscated in OpenSSL. 20049c2daa00SOllivier Robert */ 20059c2daa00SOllivier Robert /* 20069c2daa00SOllivier Robert * The basic_constraints extension CA:TRUE allows servers to 20079c2daa00SOllivier Robert * sign client certficitates. 20089c2daa00SOllivier Robert */ 20099c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_basic_constraints, 20109c2daa00SOllivier Robert BASIC_CONSTRAINTS); 20119c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, 20122b15cb3dSCy Schubert _UC(BASIC_CONSTRAINTS)); 20139c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20149c2daa00SOllivier Robert fprintf(stderr, "Add extension field fails\n%s\n", 20159c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20169c2daa00SOllivier Robert return (0); 20179c2daa00SOllivier Robert } 20189c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20199c2daa00SOllivier Robert 20209c2daa00SOllivier Robert /* 20219c2daa00SOllivier Robert * The key_usage extension designates the purposes the key can 20229c2daa00SOllivier Robert * be used for. 20239c2daa00SOllivier Robert */ 20249c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_key_usage, KEY_USAGE); 20252b15cb3dSCy Schubert ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, _UC(KEY_USAGE)); 20269c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20279c2daa00SOllivier Robert fprintf(stderr, "Add extension field fails\n%s\n", 20289c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20299c2daa00SOllivier Robert return (0); 20309c2daa00SOllivier Robert } 20319c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20329c2daa00SOllivier Robert /* 20339c2daa00SOllivier Robert * The subject_key_identifier is used for the GQ public key. 20349c2daa00SOllivier Robert * This should not be controversial. 20359c2daa00SOllivier Robert */ 20369c2daa00SOllivier Robert if (gqpub != NULL) { 20379c2daa00SOllivier Robert fprintf(stderr, "%s\n", LN_subject_key_identifier); 20389c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, 20399c2daa00SOllivier Robert NID_subject_key_identifier, gqpub); 20409c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20419c2daa00SOllivier Robert fprintf(stderr, 20429c2daa00SOllivier Robert "Add extension field fails\n%s\n", 20439c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20449c2daa00SOllivier Robert return (0); 20459c2daa00SOllivier Robert } 20469c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20479c2daa00SOllivier Robert } 20489c2daa00SOllivier Robert 20499c2daa00SOllivier Robert /* 20509c2daa00SOllivier Robert * The extended key usage extension is used for special purpose 20519c2daa00SOllivier Robert * here. The semantics probably do not conform to the designer's 20529c2daa00SOllivier Robert * intent and will likely change in future. 20539c2daa00SOllivier Robert * 20549c2daa00SOllivier Robert * "trustRoot" designates a root authority 20559c2daa00SOllivier Robert * "private" designates a private certificate 20569c2daa00SOllivier Robert */ 20579c2daa00SOllivier Robert if (exten != NULL) { 20589c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_ext_key_usage, exten); 20599c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, 20602b15cb3dSCy Schubert NID_ext_key_usage, _UC(exten)); 20619c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20629c2daa00SOllivier Robert fprintf(stderr, 20639c2daa00SOllivier Robert "Add extension field fails\n%s\n", 20649c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20659c2daa00SOllivier Robert return (0); 20669c2daa00SOllivier Robert } 20679c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20689c2daa00SOllivier Robert } 20699c2daa00SOllivier Robert 20709c2daa00SOllivier Robert /* 20719c2daa00SOllivier Robert * Sign and verify. 20729c2daa00SOllivier Robert */ 20739c2daa00SOllivier Robert X509_sign(cert, pkey, md); 20742b15cb3dSCy Schubert if (X509_verify(cert, pkey) <= 0) { 20759c2daa00SOllivier Robert fprintf(stderr, "Verify %s certificate fails\n%s\n", id, 20769c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20779c2daa00SOllivier Robert X509_free(cert); 20789c2daa00SOllivier Robert return (0); 20799c2daa00SOllivier Robert } 20809c2daa00SOllivier Robert 20819c2daa00SOllivier Robert /* 20829c2daa00SOllivier Robert * Write the certificate encoded in PEM. 20839c2daa00SOllivier Robert */ 20842b15cb3dSCy Schubert snprintf(pathbuf, sizeof(pathbuf), "%scert", id); 20852b15cb3dSCy Schubert str = fheader(pathbuf, "cert", hostname); 20869c2daa00SOllivier Robert PEM_write_X509(str, cert); 20879c2daa00SOllivier Robert fclose(str); 20889c2daa00SOllivier Robert if (debug) 20892b15cb3dSCy Schubert X509_print_fp(stderr, cert); 20909c2daa00SOllivier Robert X509_free(cert); 20919c2daa00SOllivier Robert return (1); 20929c2daa00SOllivier Robert } 20939c2daa00SOllivier Robert 20942b15cb3dSCy Schubert #if 0 /* asn2ntp is used only with commercial certificates */ 20959c2daa00SOllivier Robert /* 20969c2daa00SOllivier Robert * asn2ntp - convert ASN1_TIME time structure to NTP time 20979c2daa00SOllivier Robert */ 20989c2daa00SOllivier Robert u_long 20999c2daa00SOllivier Robert asn2ntp ( 21009c2daa00SOllivier Robert ASN1_TIME *asn1time /* pointer to ASN1_TIME structure */ 21019c2daa00SOllivier Robert ) 21029c2daa00SOllivier Robert { 21039c2daa00SOllivier Robert char *v; /* pointer to ASN1_TIME string */ 21049c2daa00SOllivier Robert struct tm tm; /* time decode structure time */ 21059c2daa00SOllivier Robert 21069c2daa00SOllivier Robert /* 21079c2daa00SOllivier Robert * Extract time string YYMMDDHHMMSSZ from ASN.1 time structure. 21089c2daa00SOllivier Robert * Note that the YY, MM, DD fields start with one, the HH, MM, 21099c2daa00SOllivier Robert * SS fiels start with zero and the Z character should be 'Z' 21109c2daa00SOllivier Robert * for UTC. Also note that years less than 50 map to years 21119c2daa00SOllivier Robert * greater than 100. Dontcha love ASN.1? 21129c2daa00SOllivier Robert */ 21139c2daa00SOllivier Robert if (asn1time->length > 13) 21149c2daa00SOllivier Robert return (-1); 21159c2daa00SOllivier Robert v = (char *)asn1time->data; 21169c2daa00SOllivier Robert tm.tm_year = (v[0] - '0') * 10 + v[1] - '0'; 21179c2daa00SOllivier Robert if (tm.tm_year < 50) 21189c2daa00SOllivier Robert tm.tm_year += 100; 21199c2daa00SOllivier Robert tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1; 21209c2daa00SOllivier Robert tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0'; 21219c2daa00SOllivier Robert tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0'; 21229c2daa00SOllivier Robert tm.tm_min = (v[8] - '0') * 10 + v[9] - '0'; 21239c2daa00SOllivier Robert tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0'; 21249c2daa00SOllivier Robert tm.tm_wday = 0; 21259c2daa00SOllivier Robert tm.tm_yday = 0; 21269c2daa00SOllivier Robert tm.tm_isdst = 0; 21279c2daa00SOllivier Robert return (mktime(&tm) + JAN_1970); 21289c2daa00SOllivier Robert } 21299c2daa00SOllivier Robert #endif 21309c2daa00SOllivier Robert 21319c2daa00SOllivier Robert /* 21329c2daa00SOllivier Robert * Callback routine 21339c2daa00SOllivier Robert */ 21349c2daa00SOllivier Robert void 21359c2daa00SOllivier Robert cb ( 21369c2daa00SOllivier Robert int n1, /* arg 1 */ 21379c2daa00SOllivier Robert int n2, /* arg 2 */ 21389c2daa00SOllivier Robert void *chr /* arg 3 */ 21399c2daa00SOllivier Robert ) 21409c2daa00SOllivier Robert { 21419c2daa00SOllivier Robert switch (n1) { 21429c2daa00SOllivier Robert case 0: 21439c2daa00SOllivier Robert d0++; 21449c2daa00SOllivier Robert fprintf(stderr, "%s %d %d %lu\r", (char *)chr, n1, n2, 21459c2daa00SOllivier Robert d0); 21469c2daa00SOllivier Robert break; 21479c2daa00SOllivier Robert case 1: 21489c2daa00SOllivier Robert d1++; 21499c2daa00SOllivier Robert fprintf(stderr, "%s\t\t%d %d %lu\r", (char *)chr, n1, 21509c2daa00SOllivier Robert n2, d1); 21519c2daa00SOllivier Robert break; 21529c2daa00SOllivier Robert case 2: 21539c2daa00SOllivier Robert d2++; 21549c2daa00SOllivier Robert fprintf(stderr, "%s\t\t\t\t%d %d %lu\r", (char *)chr, 21559c2daa00SOllivier Robert n1, n2, d2); 21569c2daa00SOllivier Robert break; 21579c2daa00SOllivier Robert case 3: 21589c2daa00SOllivier Robert d3++; 21599c2daa00SOllivier Robert fprintf(stderr, "%s\t\t\t\t\t\t%d %d %lu\r", 21609c2daa00SOllivier Robert (char *)chr, n1, n2, d3); 21619c2daa00SOllivier Robert break; 21629c2daa00SOllivier Robert } 21639c2daa00SOllivier Robert } 21649c2daa00SOllivier Robert 21659c2daa00SOllivier Robert 21669c2daa00SOllivier Robert /* 21679c2daa00SOllivier Robert * Generate key 21689c2daa00SOllivier Robert */ 21699c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 21709c2daa00SOllivier Robert genkey( 21712b15cb3dSCy Schubert const char *type, /* key type (RSA or DSA) */ 21722b15cb3dSCy Schubert const char *id /* file name id */ 21739c2daa00SOllivier Robert ) 21749c2daa00SOllivier Robert { 21759c2daa00SOllivier Robert if (type == NULL) 21769c2daa00SOllivier Robert return (NULL); 21779c2daa00SOllivier Robert if (strcmp(type, "RSA") == 0) 21789c2daa00SOllivier Robert return (gen_rsa(id)); 21799c2daa00SOllivier Robert 21809c2daa00SOllivier Robert else if (strcmp(type, "DSA") == 0) 21819c2daa00SOllivier Robert return (gen_dsa(id)); 21829c2daa00SOllivier Robert 21839c2daa00SOllivier Robert fprintf(stderr, "Invalid %s key type %s\n", id, type); 21849c2daa00SOllivier Robert return (NULL); 21859c2daa00SOllivier Robert } 2186f391d6bcSXin LI 2187f391d6bcSXin LI static RSA* 2188f391d6bcSXin LI genRsaKeyPair( 2189f391d6bcSXin LI int bits, 2190f391d6bcSXin LI char * what 2191f391d6bcSXin LI ) 2192f391d6bcSXin LI { 2193f391d6bcSXin LI RSA * rsa = RSA_new(); 2194f391d6bcSXin LI BN_GENCB * gcb = BN_GENCB_new(); 2195f391d6bcSXin LI BIGNUM * bne = BN_new(); 2196f391d6bcSXin LI 2197f391d6bcSXin LI if (gcb) 2198f391d6bcSXin LI BN_GENCB_set_old(gcb, cb, what); 2199f391d6bcSXin LI if (bne) 2200f391d6bcSXin LI BN_set_word(bne, 65537); 2201f391d6bcSXin LI if (!(rsa && gcb && bne && RSA_generate_key_ex( 2202f391d6bcSXin LI rsa, bits, bne, gcb))) 2203f391d6bcSXin LI { 2204f391d6bcSXin LI RSA_free(rsa); 2205f391d6bcSXin LI rsa = NULL; 2206f391d6bcSXin LI } 2207f391d6bcSXin LI BN_GENCB_free(gcb); 2208f391d6bcSXin LI BN_free(bne); 2209f391d6bcSXin LI return rsa; 2210f391d6bcSXin LI } 2211f391d6bcSXin LI 2212f391d6bcSXin LI static DSA* 2213f391d6bcSXin LI genDsaParams( 2214f391d6bcSXin LI int bits, 2215f391d6bcSXin LI char * what 2216f391d6bcSXin LI ) 2217f391d6bcSXin LI { 2218f391d6bcSXin LI 2219f391d6bcSXin LI DSA * dsa = DSA_new(); 2220f391d6bcSXin LI BN_GENCB * gcb = BN_GENCB_new(); 2221f391d6bcSXin LI u_char seed[20]; 2222f391d6bcSXin LI 2223f391d6bcSXin LI if (gcb) 2224f391d6bcSXin LI BN_GENCB_set_old(gcb, cb, what); 2225f391d6bcSXin LI RAND_bytes(seed, sizeof(seed)); 2226f391d6bcSXin LI if (!(dsa && gcb && DSA_generate_parameters_ex( 2227f391d6bcSXin LI dsa, bits, seed, sizeof(seed), NULL, NULL, gcb))) 2228f391d6bcSXin LI { 2229f391d6bcSXin LI DSA_free(dsa); 2230f391d6bcSXin LI dsa = NULL; 2231f391d6bcSXin LI } 2232f391d6bcSXin LI BN_GENCB_free(gcb); 2233f391d6bcSXin LI return dsa; 2234f391d6bcSXin LI } 2235f391d6bcSXin LI 22362b15cb3dSCy Schubert #endif /* AUTOKEY */ 22379c2daa00SOllivier Robert 22389c2daa00SOllivier Robert 22399c2daa00SOllivier Robert /* 22402b15cb3dSCy Schubert * Generate file header and link 22419c2daa00SOllivier Robert */ 22429c2daa00SOllivier Robert FILE * 22439c2daa00SOllivier Robert fheader ( 22442b15cb3dSCy Schubert const char *file, /* file name id */ 22452b15cb3dSCy Schubert const char *ulink, /* linkname */ 22462b15cb3dSCy Schubert const char *owner /* owner name */ 22479c2daa00SOllivier Robert ) 22489c2daa00SOllivier Robert { 22499c2daa00SOllivier Robert FILE *str; /* file handle */ 22502b15cb3dSCy Schubert char linkname[MAXFILENAME]; /* link name */ 22512b15cb3dSCy Schubert int temp; 2252a25439b6SCy Schubert #ifdef HAVE_UMASK 2253a25439b6SCy Schubert mode_t orig_umask; 2254a25439b6SCy Schubert #endif 22559c2daa00SOllivier Robert 22562b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_%s_%s.%u", file, 22572b15cb3dSCy Schubert owner, fstamp); 2258a25439b6SCy Schubert #ifdef HAVE_UMASK 2259a25439b6SCy Schubert orig_umask = umask( S_IWGRP | S_IRWXO ); 2260a25439b6SCy Schubert str = fopen(filename, "w"); 2261a25439b6SCy Schubert (void) umask(orig_umask); 2262a25439b6SCy Schubert #else 2263a25439b6SCy Schubert str = fopen(filename, "w"); 2264a25439b6SCy Schubert #endif 2265a25439b6SCy Schubert if (str == NULL) { 22669c2daa00SOllivier Robert perror("Write"); 22679c2daa00SOllivier Robert exit (-1); 22689c2daa00SOllivier Robert } 2269a25439b6SCy Schubert if (strcmp(ulink, "md5") == 0) { 2270a25439b6SCy Schubert strcpy(linkname,"ntp.keys"); 2271a25439b6SCy Schubert } else { 22722b15cb3dSCy Schubert snprintf(linkname, sizeof(linkname), "ntpkey_%s_%s", ulink, 22732b15cb3dSCy Schubert hostname); 2274a25439b6SCy Schubert } 22752b15cb3dSCy Schubert (void)remove(linkname); /* The symlink() line below matters */ 22769c2daa00SOllivier Robert temp = symlink(filename, linkname); 22779c2daa00SOllivier Robert if (temp < 0) 22782b15cb3dSCy Schubert perror(file); 22792b15cb3dSCy Schubert fprintf(stderr, "Generating new %s file and link\n", ulink); 22809c2daa00SOllivier Robert fprintf(stderr, "%s->%s\n", linkname, filename); 22812b15cb3dSCy Schubert fprintf(str, "# %s\n# %s\n", filename, ctime(&epoch)); 22822b15cb3dSCy Schubert return (str); 22839c2daa00SOllivier Robert } 2284