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 1019c2daa00SOllivier Robert #include "openssl/bn.h" 1029c2daa00SOllivier Robert #include "openssl/evp.h" 1039c2daa00SOllivier Robert #include "openssl/err.h" 1049c2daa00SOllivier Robert #include "openssl/rand.h" 1059c2daa00SOllivier Robert #include "openssl/pem.h" 1069c2daa00SOllivier Robert #include "openssl/x509v3.h" 1079c2daa00SOllivier Robert #include <openssl/objects.h> 108*f391d6bcSXin LI #include "libssl_compat.h" 1099c2daa00SOllivier Robert #endif /* OPENSSL */ 1102b15cb3dSCy Schubert #include <ssl_applink.c> 1119c2daa00SOllivier Robert 1122b15cb3dSCy Schubert #define _UC(str) ((char *)(intptr_t)(str)) 1139c2daa00SOllivier Robert /* 1149c2daa00SOllivier Robert * Cryptodefines 1159c2daa00SOllivier Robert */ 1162b15cb3dSCy Schubert #define MD5KEYS 10 /* number of keys generated of each type */ 1172b15cb3dSCy Schubert #define MD5SIZE 20 /* maximum key size */ 1182b15cb3dSCy Schubert #ifdef AUTOKEY 1199c2daa00SOllivier Robert #define PLEN 512 /* default prime modulus size (bits) */ 1202b15cb3dSCy Schubert #define ILEN 256 /* default identity modulus size (bits) */ 1212b15cb3dSCy Schubert #define MVMAX 100 /* max MV parameters */ 1229c2daa00SOllivier Robert 1239c2daa00SOllivier Robert /* 1249c2daa00SOllivier Robert * Strings used in X509v3 extension fields 1259c2daa00SOllivier Robert */ 1269c2daa00SOllivier Robert #define KEY_USAGE "digitalSignature,keyCertSign" 1279c2daa00SOllivier Robert #define BASIC_CONSTRAINTS "critical,CA:TRUE" 1289c2daa00SOllivier Robert #define EXT_KEY_PRIVATE "private" 1299c2daa00SOllivier Robert #define EXT_KEY_TRUST "trustRoot" 1302b15cb3dSCy Schubert #endif /* AUTOKEY */ 1319c2daa00SOllivier Robert 1329c2daa00SOllivier Robert /* 1339c2daa00SOllivier Robert * Prototypes 1349c2daa00SOllivier Robert */ 1352b15cb3dSCy Schubert FILE *fheader (const char *, const char *, const char *); 1362b15cb3dSCy Schubert int gen_md5 (const char *); 1372b15cb3dSCy Schubert void followlink (char *, size_t); 1382b15cb3dSCy Schubert #ifdef AUTOKEY 1392b15cb3dSCy Schubert EVP_PKEY *gen_rsa (const char *); 1402b15cb3dSCy Schubert EVP_PKEY *gen_dsa (const char *); 1412b15cb3dSCy Schubert EVP_PKEY *gen_iffkey (const char *); 1422b15cb3dSCy Schubert EVP_PKEY *gen_gqkey (const char *); 1432b15cb3dSCy Schubert EVP_PKEY *gen_mvkey (const char *, EVP_PKEY **); 1442b15cb3dSCy Schubert void gen_mvserv (char *, EVP_PKEY **); 1452b15cb3dSCy Schubert int x509 (EVP_PKEY *, const EVP_MD *, char *, const char *, 1462b15cb3dSCy Schubert char *); 1472b15cb3dSCy Schubert void cb (int, int, void *); 1482b15cb3dSCy Schubert EVP_PKEY *genkey (const char *, const char *); 1492b15cb3dSCy Schubert EVP_PKEY *readkey (char *, char *, u_int *, EVP_PKEY **); 1502b15cb3dSCy Schubert void writekey (char *, char *, u_int *, EVP_PKEY **); 1512b15cb3dSCy Schubert u_long asn2ntp (ASN1_TIME *); 152*f391d6bcSXin LI 153*f391d6bcSXin LI static DSA* genDsaParams(int, char*); 154*f391d6bcSXin LI static RSA* genRsaKeyPair(int, char*); 155*f391d6bcSXin LI 1562b15cb3dSCy Schubert #endif /* AUTOKEY */ 1579c2daa00SOllivier Robert 1589c2daa00SOllivier Robert /* 1599c2daa00SOllivier Robert * Program variables 1609c2daa00SOllivier Robert */ 1619c2daa00SOllivier Robert extern char *optarg; /* command line argument */ 1629034852cSGleb Smirnoff char const *progname; 1632b15cb3dSCy Schubert u_int lifetime = DAYSPERYEAR; /* certificate lifetime (days) */ 1642b15cb3dSCy Schubert int nkeys; /* MV keys */ 1659c2daa00SOllivier Robert time_t epoch; /* Unix epoch (seconds) since 1970 */ 1662b15cb3dSCy Schubert u_int fstamp; /* NTP filestamp */ 1672b15cb3dSCy Schubert char hostbuf[MAXHOSTNAME + 1]; 1682b15cb3dSCy Schubert char *hostname = NULL; /* host, used in cert filenames */ 1692b15cb3dSCy Schubert char *groupname = NULL; /* group name */ 1702b15cb3dSCy Schubert char certnamebuf[2 * sizeof(hostbuf)]; 1712b15cb3dSCy Schubert char *certname = NULL; /* certificate subject/issuer name */ 1729c2daa00SOllivier Robert char *passwd1 = NULL; /* input private key password */ 1739c2daa00SOllivier Robert char *passwd2 = NULL; /* output private key password */ 1742b15cb3dSCy Schubert char filename[MAXFILENAME + 1]; /* file name */ 1752b15cb3dSCy Schubert #ifdef AUTOKEY 1762b15cb3dSCy Schubert u_int modulus = PLEN; /* prime modulus size (bits) */ 1772b15cb3dSCy Schubert u_int modulus2 = ILEN; /* identity modulus size (bits) */ 1789c2daa00SOllivier Robert long d0, d1, d2, d3; /* callback counters */ 1792b15cb3dSCy Schubert const EVP_CIPHER * cipher = NULL; 1802b15cb3dSCy Schubert #endif /* AUTOKEY */ 1819c2daa00SOllivier Robert 1829c2daa00SOllivier Robert #ifdef SYS_WINNT 1839c2daa00SOllivier Robert BOOL init_randfile(); 1849c2daa00SOllivier Robert 1859c2daa00SOllivier Robert /* 1862b15cb3dSCy Schubert * Don't try to follow symbolic links on Windows. Assume link == file. 1879c2daa00SOllivier Robert */ 1889c2daa00SOllivier Robert int 1892b15cb3dSCy Schubert readlink( 1902b15cb3dSCy Schubert char * link, 1912b15cb3dSCy Schubert char * file, 1922b15cb3dSCy Schubert int len 1932b15cb3dSCy Schubert ) 1942b15cb3dSCy Schubert { 1953311ff84SXin LI return (int)strlen(file); /* assume no overflow possible */ 1969c2daa00SOllivier Robert } 1972b15cb3dSCy Schubert 1989c2daa00SOllivier Robert /* 1992b15cb3dSCy Schubert * Don't try to create symbolic links on Windows, that is supported on 2002b15cb3dSCy Schubert * Vista and later only. Instead, if CreateHardLink is available (XP 2012b15cb3dSCy Schubert * and later), hardlink the linkname to the original filename. On 2022b15cb3dSCy Schubert * earlier systems, user must rename file to match expected link for 2032b15cb3dSCy Schubert * ntpd to find it. To allow building a ntp-keygen.exe which loads on 2042b15cb3dSCy Schubert * Windows pre-XP, runtime link to CreateHardLinkA(). 2059c2daa00SOllivier Robert */ 2069c2daa00SOllivier Robert int 2072b15cb3dSCy Schubert symlink( 2082b15cb3dSCy Schubert char * filename, 2092b15cb3dSCy Schubert char* linkname 2102b15cb3dSCy Schubert ) 2112b15cb3dSCy Schubert { 2122b15cb3dSCy Schubert typedef BOOL (WINAPI *PCREATEHARDLINKA)( 2132b15cb3dSCy Schubert __in LPCSTR lpFileName, 2142b15cb3dSCy Schubert __in LPCSTR lpExistingFileName, 2152b15cb3dSCy Schubert __reserved LPSECURITY_ATTRIBUTES lpSA 2162b15cb3dSCy Schubert ); 2172b15cb3dSCy Schubert static PCREATEHARDLINKA pCreateHardLinkA; 2182b15cb3dSCy Schubert static int tried; 2192b15cb3dSCy Schubert HMODULE hDll; 2202b15cb3dSCy Schubert FARPROC pfn; 2212b15cb3dSCy Schubert int link_created; 2222b15cb3dSCy Schubert int saved_errno; 2232b15cb3dSCy Schubert 2242b15cb3dSCy Schubert if (!tried) { 2252b15cb3dSCy Schubert tried = TRUE; 2262b15cb3dSCy Schubert hDll = LoadLibrary("kernel32"); 2272b15cb3dSCy Schubert pfn = GetProcAddress(hDll, "CreateHardLinkA"); 2282b15cb3dSCy Schubert pCreateHardLinkA = (PCREATEHARDLINKA)pfn; 2299c2daa00SOllivier Robert } 2302b15cb3dSCy Schubert 2312b15cb3dSCy Schubert if (NULL == pCreateHardLinkA) { 2322b15cb3dSCy Schubert errno = ENOSYS; 2332b15cb3dSCy Schubert return -1; 2342b15cb3dSCy Schubert } 2352b15cb3dSCy Schubert 2362b15cb3dSCy Schubert link_created = (*pCreateHardLinkA)(linkname, filename, NULL); 2372b15cb3dSCy Schubert 2382b15cb3dSCy Schubert if (link_created) 2392b15cb3dSCy Schubert return 0; 2402b15cb3dSCy Schubert 2412b15cb3dSCy Schubert saved_errno = GetLastError(); /* yes we play loose */ 2422b15cb3dSCy Schubert mfprintf(stderr, "Create hard link %s to %s failed: %m\n", 2432b15cb3dSCy Schubert linkname, filename); 2442b15cb3dSCy Schubert errno = saved_errno; 2452b15cb3dSCy Schubert return -1; 2462b15cb3dSCy Schubert } 2472b15cb3dSCy Schubert 2489c2daa00SOllivier Robert void 2499c2daa00SOllivier Robert InitWin32Sockets() { 2509c2daa00SOllivier Robert WORD wVersionRequested; 2519c2daa00SOllivier Robert WSADATA wsaData; 2529c2daa00SOllivier Robert wVersionRequested = MAKEWORD(2,0); 2539c2daa00SOllivier Robert if (WSAStartup(wVersionRequested, &wsaData)) 2549c2daa00SOllivier Robert { 2552b15cb3dSCy Schubert fprintf(stderr, "No useable winsock.dll\n"); 2569c2daa00SOllivier Robert exit(1); 2579c2daa00SOllivier Robert } 2589c2daa00SOllivier Robert } 2599c2daa00SOllivier Robert #endif /* SYS_WINNT */ 2609c2daa00SOllivier Robert 2612b15cb3dSCy Schubert 2622b15cb3dSCy Schubert /* 2632b15cb3dSCy Schubert * followlink() - replace filename with its target if symlink. 2642b15cb3dSCy Schubert * 2652b15cb3dSCy Schubert * Some readlink() implementations do not null-terminate the result. 2662b15cb3dSCy Schubert */ 2672b15cb3dSCy Schubert void 2682b15cb3dSCy Schubert followlink( 2692b15cb3dSCy Schubert char * fname, 2702b15cb3dSCy Schubert size_t bufsiz 2712b15cb3dSCy Schubert ) 2722b15cb3dSCy Schubert { 2732b15cb3dSCy Schubert int len; 2742b15cb3dSCy Schubert 2752b15cb3dSCy Schubert REQUIRE(bufsiz > 0); 2762b15cb3dSCy Schubert 2772b15cb3dSCy Schubert len = readlink(fname, fname, (int)bufsiz); 2782b15cb3dSCy Schubert if (len < 0 ) { 2792b15cb3dSCy Schubert fname[0] = '\0'; 2802b15cb3dSCy Schubert return; 2812b15cb3dSCy Schubert } 2822b15cb3dSCy Schubert if (len > (int)bufsiz - 1) 2832b15cb3dSCy Schubert len = (int)bufsiz - 1; 2842b15cb3dSCy Schubert fname[len] = '\0'; 2852b15cb3dSCy Schubert } 2862b15cb3dSCy Schubert 2872b15cb3dSCy Schubert 2889c2daa00SOllivier Robert /* 2899c2daa00SOllivier Robert * Main program 2909c2daa00SOllivier Robert */ 2919c2daa00SOllivier Robert int 2929c2daa00SOllivier Robert main( 2939c2daa00SOllivier Robert int argc, /* command line options */ 2949c2daa00SOllivier Robert char **argv 2959c2daa00SOllivier Robert ) 2969c2daa00SOllivier Robert { 2979c2daa00SOllivier Robert struct timeval tv; /* initialization vector */ 298ea906c41SOllivier Robert int md5key = 0; /* generate MD5 keys */ 2992b15cb3dSCy Schubert int optct; /* option count */ 3002b15cb3dSCy Schubert #ifdef AUTOKEY 3019c2daa00SOllivier Robert X509 *cert = NULL; /* X509 certificate */ 3029c2daa00SOllivier Robert EVP_PKEY *pkey_host = NULL; /* host key */ 3039c2daa00SOllivier Robert EVP_PKEY *pkey_sign = NULL; /* sign key */ 3042b15cb3dSCy Schubert EVP_PKEY *pkey_iffkey = NULL; /* IFF sever keys */ 3052b15cb3dSCy Schubert EVP_PKEY *pkey_gqkey = NULL; /* GQ server keys */ 3062b15cb3dSCy Schubert EVP_PKEY *pkey_mvkey = NULL; /* MV trusted agen keys */ 3072b15cb3dSCy Schubert EVP_PKEY *pkey_mvpar[MVMAX]; /* MV cleient keys */ 3089c2daa00SOllivier Robert int hostkey = 0; /* generate RSA keys */ 3092b15cb3dSCy Schubert int iffkey = 0; /* generate IFF keys */ 3102b15cb3dSCy Schubert int gqkey = 0; /* generate GQ keys */ 3119c2daa00SOllivier Robert int mvkey = 0; /* update MV keys */ 3122b15cb3dSCy Schubert int mvpar = 0; /* generate MV parameters */ 3139c2daa00SOllivier Robert char *sign = NULL; /* sign key */ 3149c2daa00SOllivier Robert EVP_PKEY *pkey = NULL; /* temp key */ 3159c2daa00SOllivier Robert const EVP_MD *ectx; /* EVP digest */ 3169c2daa00SOllivier Robert char pathbuf[MAXFILENAME + 1]; 3179c2daa00SOllivier Robert const char *scheme = NULL; /* digest/signature scheme */ 3182b15cb3dSCy Schubert const char *ciphername = NULL; /* to encrypt priv. key */ 3192b15cb3dSCy Schubert const char *exten = NULL; /* private extension */ 3209c2daa00SOllivier Robert char *grpkey = NULL; /* identity extension */ 3219c2daa00SOllivier Robert int nid; /* X509 digest/signature scheme */ 3229c2daa00SOllivier Robert FILE *fstr = NULL; /* file handle */ 3232b15cb3dSCy Schubert char groupbuf[MAXHOSTNAME + 1]; 324ea906c41SOllivier Robert u_int temp; 3252b15cb3dSCy Schubert BIO * bp; 3262b15cb3dSCy Schubert int i, cnt; 3272b15cb3dSCy Schubert char * ptr; 3282b15cb3dSCy Schubert #endif /* AUTOKEY */ 3292b15cb3dSCy Schubert 3302b15cb3dSCy Schubert progname = argv[0]; 3319c2daa00SOllivier Robert 3329c2daa00SOllivier Robert #ifdef SYS_WINNT 3339c2daa00SOllivier Robert /* Initialize before OpenSSL checks */ 3349c2daa00SOllivier Robert InitWin32Sockets(); 3359c2daa00SOllivier Robert if (!init_randfile()) 3369c2daa00SOllivier Robert fprintf(stderr, "Unable to initialize .rnd file\n"); 3372b15cb3dSCy Schubert ssl_applink(); 3389c2daa00SOllivier Robert #endif 3399c2daa00SOllivier Robert 3409c2daa00SOllivier Robert #ifdef OPENSSL 3412b15cb3dSCy Schubert ssl_check_version(); 3429c2daa00SOllivier Robert #endif /* OPENSSL */ 3439c2daa00SOllivier Robert 3442b15cb3dSCy Schubert ntp_crypto_srandom(); 3452b15cb3dSCy Schubert 3469c2daa00SOllivier Robert /* 3479c2daa00SOllivier Robert * Process options, initialize host name and timestamp. 3482b15cb3dSCy Schubert * gethostname() won't null-terminate if hostname is exactly the 3492b15cb3dSCy Schubert * length provided for the buffer. 3509c2daa00SOllivier Robert */ 3512b15cb3dSCy Schubert gethostname(hostbuf, sizeof(hostbuf) - 1); 3522b15cb3dSCy Schubert hostbuf[COUNTOF(hostbuf) - 1] = '\0'; 3539c2daa00SOllivier Robert hostname = hostbuf; 3542b15cb3dSCy Schubert groupname = hostbuf; 3559c2daa00SOllivier Robert passwd1 = hostbuf; 3562b15cb3dSCy Schubert passwd2 = NULL; 3572b15cb3dSCy Schubert GETTIMEOFDAY(&tv, NULL); 3589c2daa00SOllivier Robert epoch = tv.tv_sec; 3592b15cb3dSCy Schubert fstamp = (u_int)(epoch + JAN_1970); 360ea906c41SOllivier Robert 3612b15cb3dSCy Schubert optct = ntpOptionProcess(&ntp_keygenOptions, argc, argv); 3629034852cSGleb Smirnoff argc -= optct; // Just in case we care later. 3639034852cSGleb Smirnoff argv += optct; // Just in case we care later. 3649c2daa00SOllivier Robert 3655e91a9b7SOllivier Robert #ifdef OPENSSL 3662b15cb3dSCy Schubert if (SSLeay() == SSLEAY_VERSION_NUMBER) 3672b15cb3dSCy Schubert fprintf(stderr, "Using OpenSSL version %s\n", 3682b15cb3dSCy Schubert SSLeay_version(SSLEAY_VERSION)); 3692b15cb3dSCy Schubert else 3702b15cb3dSCy Schubert fprintf(stderr, "Built against OpenSSL %s, using version %s\n", 3712b15cb3dSCy Schubert OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION)); 3722b15cb3dSCy Schubert #endif /* OPENSSL */ 3739c2daa00SOllivier Robert 3742b15cb3dSCy Schubert debug = OPT_VALUE_SET_DEBUG_LEVEL; 3759c2daa00SOllivier Robert 3762b15cb3dSCy Schubert if (HAVE_OPT( MD5KEY )) 3772b15cb3dSCy Schubert md5key++; 3782b15cb3dSCy Schubert #ifdef AUTOKEY 3792b15cb3dSCy Schubert if (HAVE_OPT( PASSWORD )) 3802b15cb3dSCy Schubert passwd1 = estrdup(OPT_ARG( PASSWORD )); 3819c2daa00SOllivier Robert 3822b15cb3dSCy Schubert if (HAVE_OPT( EXPORT_PASSWD )) 3832b15cb3dSCy Schubert passwd2 = estrdup(OPT_ARG( EXPORT_PASSWD )); 3849c2daa00SOllivier Robert 385ea906c41SOllivier Robert if (HAVE_OPT( HOST_KEY )) 3869c2daa00SOllivier Robert hostkey++; 3879c2daa00SOllivier Robert 3882b15cb3dSCy Schubert if (HAVE_OPT( SIGN_KEY )) 3892b15cb3dSCy Schubert sign = estrdup(OPT_ARG( SIGN_KEY )); 3902b15cb3dSCy Schubert 3912b15cb3dSCy Schubert if (HAVE_OPT( GQ_PARAMS )) 3922b15cb3dSCy Schubert gqkey++; 3932b15cb3dSCy Schubert 394ea906c41SOllivier Robert if (HAVE_OPT( IFFKEY )) 3959c2daa00SOllivier Robert iffkey++; 396ea906c41SOllivier Robert 3972b15cb3dSCy Schubert if (HAVE_OPT( MV_PARAMS )) { 3982b15cb3dSCy Schubert mvkey++; 3992b15cb3dSCy Schubert nkeys = OPT_VALUE_MV_PARAMS; 4002b15cb3dSCy Schubert } 4012b15cb3dSCy Schubert if (HAVE_OPT( MV_KEYS )) { 4022b15cb3dSCy Schubert mvpar++; 4032b15cb3dSCy Schubert nkeys = OPT_VALUE_MV_KEYS; 4042b15cb3dSCy Schubert } 4059c2daa00SOllivier Robert 4062b15cb3dSCy Schubert if (HAVE_OPT( IMBITS )) 4072b15cb3dSCy Schubert modulus2 = OPT_VALUE_IMBITS; 4089c2daa00SOllivier Robert 409ea906c41SOllivier Robert if (HAVE_OPT( MODULUS )) 410ea906c41SOllivier Robert modulus = OPT_VALUE_MODULUS; 4119c2daa00SOllivier Robert 4122b15cb3dSCy Schubert if (HAVE_OPT( CERTIFICATE )) 4132b15cb3dSCy Schubert scheme = OPT_ARG( CERTIFICATE ); 4142b15cb3dSCy Schubert 4152b15cb3dSCy Schubert if (HAVE_OPT( CIPHER )) 4162b15cb3dSCy Schubert ciphername = OPT_ARG( CIPHER ); 4172b15cb3dSCy Schubert 4182b15cb3dSCy Schubert if (HAVE_OPT( SUBJECT_NAME )) 4192b15cb3dSCy Schubert hostname = estrdup(OPT_ARG( SUBJECT_NAME )); 4202b15cb3dSCy Schubert 4212b15cb3dSCy Schubert if (HAVE_OPT( IDENT )) 4222b15cb3dSCy Schubert groupname = estrdup(OPT_ARG( IDENT )); 4232b15cb3dSCy Schubert 4242b15cb3dSCy Schubert if (HAVE_OPT( LIFETIME )) 4252b15cb3dSCy Schubert lifetime = OPT_VALUE_LIFETIME; 4262b15cb3dSCy Schubert 427ea906c41SOllivier Robert if (HAVE_OPT( PVT_CERT )) 4289c2daa00SOllivier Robert exten = EXT_KEY_PRIVATE; 4299c2daa00SOllivier Robert 430ea906c41SOllivier Robert if (HAVE_OPT( TRUSTED_CERT )) 4319c2daa00SOllivier Robert exten = EXT_KEY_TRUST; 4329c2daa00SOllivier Robert 4332b15cb3dSCy Schubert /* 4342b15cb3dSCy Schubert * Remove the group name from the hostname variable used 4352b15cb3dSCy Schubert * in host and sign certificate file names. 4362b15cb3dSCy Schubert */ 4372b15cb3dSCy Schubert if (hostname != hostbuf) 4382b15cb3dSCy Schubert ptr = strchr(hostname, '@'); 4392b15cb3dSCy Schubert else 4402b15cb3dSCy Schubert ptr = NULL; 4412b15cb3dSCy Schubert if (ptr != NULL) { 4422b15cb3dSCy Schubert *ptr = '\0'; 4432b15cb3dSCy Schubert groupname = estrdup(ptr + 1); 4442b15cb3dSCy Schubert /* -s @group is equivalent to -i group, host unch. */ 4452b15cb3dSCy Schubert if (ptr == hostname) 4462b15cb3dSCy Schubert hostname = hostbuf; 447ea906c41SOllivier Robert } 4489c2daa00SOllivier Robert 4492b15cb3dSCy Schubert /* 4502b15cb3dSCy Schubert * Derive host certificate issuer/subject names from host name 4512b15cb3dSCy Schubert * and optional group. If no groupname is provided, the issuer 4522b15cb3dSCy Schubert * and subject is the hostname with no '@group', and the 4532b15cb3dSCy Schubert * groupname variable is pointed to hostname for use in IFF, GQ, 4542b15cb3dSCy Schubert * and MV parameters file names. 4552b15cb3dSCy Schubert */ 4562b15cb3dSCy Schubert if (groupname == hostbuf) { 4572b15cb3dSCy Schubert certname = hostname; 4582b15cb3dSCy Schubert } else { 4592b15cb3dSCy Schubert snprintf(certnamebuf, sizeof(certnamebuf), "%s@%s", 4602b15cb3dSCy Schubert hostname, groupname); 4612b15cb3dSCy Schubert certname = certnamebuf; 462ea906c41SOllivier Robert } 4639c2daa00SOllivier Robert 4649c2daa00SOllivier Robert /* 4659c2daa00SOllivier Robert * Seed random number generator and grow weeds. 4669c2daa00SOllivier Robert */ 4679c2daa00SOllivier Robert ERR_load_crypto_strings(); 4689c2daa00SOllivier Robert OpenSSL_add_all_algorithms(); 4692b15cb3dSCy Schubert if (!RAND_status()) { 4702b15cb3dSCy Schubert if (RAND_file_name(pathbuf, sizeof(pathbuf)) == NULL) { 4719c2daa00SOllivier Robert fprintf(stderr, "RAND_file_name %s\n", 4729c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 4732b15cb3dSCy Schubert exit (-1); 4749c2daa00SOllivier Robert } 4759c2daa00SOllivier Robert temp = RAND_load_file(pathbuf, -1); 4769c2daa00SOllivier Robert if (temp == 0) { 4779c2daa00SOllivier Robert fprintf(stderr, 4782b15cb3dSCy Schubert "RAND_load_file %s not found or empty\n", 4792b15cb3dSCy Schubert pathbuf); 4802b15cb3dSCy Schubert exit (-1); 4819c2daa00SOllivier Robert } 4829c2daa00SOllivier Robert fprintf(stderr, 4839c2daa00SOllivier Robert "Random seed file %s %u bytes\n", pathbuf, temp); 4849c2daa00SOllivier Robert RAND_add(&epoch, sizeof(epoch), 4.0); 4852b15cb3dSCy Schubert } 4862b15cb3dSCy Schubert #endif /* AUTOKEY */ 4879c2daa00SOllivier Robert 4889c2daa00SOllivier Robert /* 4892b15cb3dSCy Schubert * Create new unencrypted MD5 keys file if requested. If this 4902b15cb3dSCy Schubert * option is selected, ignore all other options. 4919c2daa00SOllivier Robert */ 4922b15cb3dSCy Schubert if (md5key) { 4932b15cb3dSCy Schubert gen_md5("md5"); 4942b15cb3dSCy Schubert exit (0); 4952b15cb3dSCy Schubert } 4969c2daa00SOllivier Robert 4972b15cb3dSCy Schubert #ifdef AUTOKEY 4989c2daa00SOllivier Robert /* 4992b15cb3dSCy Schubert * Load previous certificate if available. 5009c2daa00SOllivier Robert */ 5012b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_cert_%s", hostname); 5029c2daa00SOllivier Robert if ((fstr = fopen(filename, "r")) != NULL) { 5039c2daa00SOllivier Robert cert = PEM_read_X509(fstr, NULL, NULL, NULL); 5049c2daa00SOllivier Robert fclose(fstr); 5052b15cb3dSCy Schubert } 5062b15cb3dSCy Schubert if (cert != NULL) { 5072b15cb3dSCy Schubert 5082b15cb3dSCy Schubert /* 5092b15cb3dSCy Schubert * Extract subject name. 5102b15cb3dSCy Schubert */ 5112b15cb3dSCy Schubert X509_NAME_oneline(X509_get_subject_name(cert), groupbuf, 5122b15cb3dSCy Schubert MAXFILENAME); 5132b15cb3dSCy Schubert 5142b15cb3dSCy Schubert /* 5152b15cb3dSCy Schubert * Extract digest/signature scheme. 5162b15cb3dSCy Schubert */ 5172b15cb3dSCy Schubert if (scheme == NULL) { 518*f391d6bcSXin LI nid = X509_get_signature_nid(cert); 5199c2daa00SOllivier Robert scheme = OBJ_nid2sn(nid); 5202b15cb3dSCy Schubert } 5212b15cb3dSCy Schubert 5222b15cb3dSCy Schubert /* 5232b15cb3dSCy Schubert * If a key_usage extension field is present, determine 5242b15cb3dSCy Schubert * whether this is a trusted or private certificate. 5252b15cb3dSCy Schubert */ 5262b15cb3dSCy Schubert if (exten == NULL) { 5272b15cb3dSCy Schubert ptr = strstr(groupbuf, "CN="); 5282b15cb3dSCy Schubert cnt = X509_get_ext_count(cert); 5292b15cb3dSCy Schubert for (i = 0; i < cnt; i++) { 530*f391d6bcSXin LI X509_EXTENSION *ext; 531*f391d6bcSXin LI ASN1_OBJECT *obj; 532*f391d6bcSXin LI 5332b15cb3dSCy Schubert ext = X509_get_ext(cert, i); 534*f391d6bcSXin LI obj = X509_EXTENSION_get_object(ext); 535*f391d6bcSXin LI 536*f391d6bcSXin LI if (OBJ_obj2nid(obj) == 5372b15cb3dSCy Schubert NID_ext_key_usage) { 5382b15cb3dSCy Schubert bp = BIO_new(BIO_s_mem()); 5392b15cb3dSCy Schubert X509V3_EXT_print(bp, ext, 0, 0); 5402b15cb3dSCy Schubert BIO_gets(bp, pathbuf, 5412b15cb3dSCy Schubert MAXFILENAME); 5422b15cb3dSCy Schubert BIO_free(bp); 5432b15cb3dSCy Schubert if (strcmp(pathbuf, 5442b15cb3dSCy Schubert "Trust Root") == 0) 5452b15cb3dSCy Schubert exten = EXT_KEY_TRUST; 5462b15cb3dSCy Schubert else if (strcmp(pathbuf, 5472b15cb3dSCy Schubert "Private") == 0) 5482b15cb3dSCy Schubert exten = EXT_KEY_PRIVATE; 5492b15cb3dSCy Schubert certname = estrdup(ptr + 3); 5509c2daa00SOllivier Robert } 5519c2daa00SOllivier Robert } 5522b15cb3dSCy Schubert } 5532b15cb3dSCy Schubert } 5542b15cb3dSCy Schubert if (scheme == NULL) 5559c2daa00SOllivier Robert scheme = "RSA-MD5"; 5562b15cb3dSCy Schubert if (ciphername == NULL) 5572b15cb3dSCy Schubert ciphername = "des-ede3-cbc"; 5582b15cb3dSCy Schubert cipher = EVP_get_cipherbyname(ciphername); 5592b15cb3dSCy Schubert if (cipher == NULL) { 5602b15cb3dSCy Schubert fprintf(stderr, "Unknown cipher %s\n", ciphername); 5612b15cb3dSCy Schubert exit(-1); 5629c2daa00SOllivier Robert } 5632b15cb3dSCy Schubert fprintf(stderr, "Using host %s group %s\n", hostname, 5642b15cb3dSCy Schubert groupname); 5652b15cb3dSCy Schubert 5662b15cb3dSCy Schubert /* 5672b15cb3dSCy Schubert * Create a new encrypted RSA host key file if requested; 5682b15cb3dSCy Schubert * otherwise, look for an existing host key file. If not found, 5692b15cb3dSCy Schubert * create a new encrypted RSA host key file. If that fails, go 5702b15cb3dSCy Schubert * no further. 5712b15cb3dSCy Schubert */ 5722b15cb3dSCy Schubert if (hostkey) 5732b15cb3dSCy Schubert pkey_host = genkey("RSA", "host"); 5742b15cb3dSCy Schubert if (pkey_host == NULL) { 5752b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_host_%s", hostname); 5762b15cb3dSCy Schubert pkey_host = readkey(filename, passwd1, &fstamp, NULL); 5772b15cb3dSCy Schubert if (pkey_host != NULL) { 5782b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 5792b15cb3dSCy Schubert fprintf(stderr, "Using host key %s\n", 5802b15cb3dSCy Schubert filename); 5812b15cb3dSCy Schubert } else { 5822b15cb3dSCy Schubert pkey_host = genkey("RSA", "host"); 5832b15cb3dSCy Schubert } 5842b15cb3dSCy Schubert } 5852b15cb3dSCy Schubert if (pkey_host == NULL) { 5862b15cb3dSCy Schubert fprintf(stderr, "Generating host key fails\n"); 5872b15cb3dSCy Schubert exit(-1); 5882b15cb3dSCy Schubert } 5892b15cb3dSCy Schubert 5902b15cb3dSCy Schubert /* 5912b15cb3dSCy Schubert * Create new encrypted RSA or DSA sign keys file if requested; 5922b15cb3dSCy Schubert * otherwise, look for an existing sign key file. If not found, 5932b15cb3dSCy Schubert * use the host key instead. 5942b15cb3dSCy Schubert */ 5952b15cb3dSCy Schubert if (sign != NULL) 5962b15cb3dSCy Schubert pkey_sign = genkey(sign, "sign"); 5972b15cb3dSCy Schubert if (pkey_sign == NULL) { 5982b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_sign_%s", 5992b15cb3dSCy Schubert hostname); 6002b15cb3dSCy Schubert pkey_sign = readkey(filename, passwd1, &fstamp, NULL); 6012b15cb3dSCy Schubert if (pkey_sign != NULL) { 6022b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 6032b15cb3dSCy Schubert fprintf(stderr, "Using sign key %s\n", 6042b15cb3dSCy Schubert filename); 6052b15cb3dSCy Schubert } else { 6062b15cb3dSCy Schubert pkey_sign = pkey_host; 6072b15cb3dSCy Schubert fprintf(stderr, "Using host key as sign key\n"); 6082b15cb3dSCy Schubert } 6092b15cb3dSCy Schubert } 6102b15cb3dSCy Schubert 6112b15cb3dSCy Schubert /* 6122b15cb3dSCy Schubert * Create new encrypted GQ server keys file if requested; 6132b15cb3dSCy Schubert * otherwise, look for an exisiting file. If found, fetch the 6142b15cb3dSCy Schubert * public key for the certificate. 6152b15cb3dSCy Schubert */ 6162b15cb3dSCy Schubert if (gqkey) 6172b15cb3dSCy Schubert pkey_gqkey = gen_gqkey("gqkey"); 6182b15cb3dSCy Schubert if (pkey_gqkey == NULL) { 6192b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_gqkey_%s", 6202b15cb3dSCy Schubert groupname); 6212b15cb3dSCy Schubert pkey_gqkey = readkey(filename, passwd1, &fstamp, NULL); 6222b15cb3dSCy Schubert if (pkey_gqkey != NULL) { 6232b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 6242b15cb3dSCy Schubert fprintf(stderr, "Using GQ parameters %s\n", 6252b15cb3dSCy Schubert filename); 6262b15cb3dSCy Schubert } 6272b15cb3dSCy Schubert } 628*f391d6bcSXin LI if (pkey_gqkey != NULL) { 629*f391d6bcSXin LI RSA *rsa; 630*f391d6bcSXin LI const BIGNUM *q; 631*f391d6bcSXin LI 632*f391d6bcSXin LI rsa = EVP_PKEY_get0_RSA(pkey_gqkey); 633*f391d6bcSXin LI RSA_get0_factors(rsa, NULL, &q); 634*f391d6bcSXin LI grpkey = BN_bn2hex(q); 635*f391d6bcSXin LI } 6362b15cb3dSCy Schubert 6372b15cb3dSCy Schubert /* 6382b15cb3dSCy Schubert * Write the nonencrypted GQ client parameters to the stdout 6392b15cb3dSCy Schubert * stream. The parameter file is the server key file with the 6402b15cb3dSCy Schubert * private key obscured. 6412b15cb3dSCy Schubert */ 6422b15cb3dSCy Schubert if (pkey_gqkey != NULL && HAVE_OPT(ID_KEY)) { 6432b15cb3dSCy Schubert RSA *rsa; 6442b15cb3dSCy Schubert 6452b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 6462b15cb3dSCy Schubert "ntpkey_gqpar_%s.%u", groupname, fstamp); 6472b15cb3dSCy Schubert fprintf(stderr, "Writing GQ parameters %s to stdout\n", 6482b15cb3dSCy Schubert filename); 6492b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 6502b15cb3dSCy Schubert ctime(&epoch)); 651*f391d6bcSXin LI /* XXX: This modifies the private key and should probably use a 652*f391d6bcSXin LI * copy of it instead. */ 653*f391d6bcSXin LI rsa = EVP_PKEY_get0_RSA(pkey_gqkey); 654*f391d6bcSXin LI RSA_set0_factors(rsa, BN_dup(BN_value_one()), BN_dup(BN_value_one())); 6552b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 6562b15cb3dSCy Schubert EVP_PKEY_assign_RSA(pkey, rsa); 6572b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 6582b15cb3dSCy Schubert NULL, NULL); 6592b15cb3dSCy Schubert fflush(stdout); 6602b15cb3dSCy Schubert if (debug) 6612b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 6622b15cb3dSCy Schubert } 6632b15cb3dSCy Schubert 6642b15cb3dSCy Schubert /* 6652b15cb3dSCy Schubert * Write the encrypted GQ server keys to the stdout stream. 6662b15cb3dSCy Schubert */ 6672b15cb3dSCy Schubert if (pkey_gqkey != NULL && passwd2 != NULL) { 6682b15cb3dSCy Schubert RSA *rsa; 6692b15cb3dSCy Schubert 6702b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 6712b15cb3dSCy Schubert "ntpkey_gqkey_%s.%u", groupname, fstamp); 6722b15cb3dSCy Schubert fprintf(stderr, "Writing GQ keys %s to stdout\n", 6732b15cb3dSCy Schubert filename); 6742b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 6752b15cb3dSCy Schubert ctime(&epoch)); 676*f391d6bcSXin LI rsa = EVP_PKEY_get0_RSA(pkey_gqkey); 6772b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 6782b15cb3dSCy Schubert EVP_PKEY_assign_RSA(pkey, rsa); 6792b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 6802b15cb3dSCy Schubert NULL, passwd2); 6812b15cb3dSCy Schubert fflush(stdout); 6822b15cb3dSCy Schubert if (debug) 6832b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 6842b15cb3dSCy Schubert } 6852b15cb3dSCy Schubert 6862b15cb3dSCy Schubert /* 6872b15cb3dSCy Schubert * Create new encrypted IFF server keys file if requested; 6882b15cb3dSCy Schubert * otherwise, look for existing file. 6892b15cb3dSCy Schubert */ 6902b15cb3dSCy Schubert if (iffkey) 6912b15cb3dSCy Schubert pkey_iffkey = gen_iffkey("iffkey"); 6922b15cb3dSCy Schubert if (pkey_iffkey == NULL) { 6932b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_iffkey_%s", 6942b15cb3dSCy Schubert groupname); 6952b15cb3dSCy Schubert pkey_iffkey = readkey(filename, passwd1, &fstamp, NULL); 6962b15cb3dSCy Schubert if (pkey_iffkey != NULL) { 6972b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 6982b15cb3dSCy Schubert fprintf(stderr, "Using IFF keys %s\n", 6992b15cb3dSCy Schubert filename); 7002b15cb3dSCy Schubert } 7012b15cb3dSCy Schubert } 7022b15cb3dSCy Schubert 7032b15cb3dSCy Schubert /* 7042b15cb3dSCy Schubert * Write the nonencrypted IFF client parameters to the stdout 7052b15cb3dSCy Schubert * stream. The parameter file is the server key file with the 7062b15cb3dSCy Schubert * private key obscured. 7072b15cb3dSCy Schubert */ 7082b15cb3dSCy Schubert if (pkey_iffkey != NULL && HAVE_OPT(ID_KEY)) { 7092b15cb3dSCy Schubert DSA *dsa; 7102b15cb3dSCy Schubert 7112b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7122b15cb3dSCy Schubert "ntpkey_iffpar_%s.%u", groupname, fstamp); 7132b15cb3dSCy Schubert fprintf(stderr, "Writing IFF parameters %s to stdout\n", 7142b15cb3dSCy Schubert filename); 7152b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7162b15cb3dSCy Schubert ctime(&epoch)); 717*f391d6bcSXin LI /* XXX: This modifies the private key and should probably use a 718*f391d6bcSXin LI * copy of it instead. */ 719*f391d6bcSXin LI dsa = EVP_PKEY_get0_DSA(pkey_iffkey); 720*f391d6bcSXin LI DSA_set0_key(dsa, NULL, BN_dup(BN_value_one())); 7212b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 7222b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey, dsa); 7232b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 7242b15cb3dSCy Schubert NULL, NULL); 7252b15cb3dSCy Schubert fflush(stdout); 7262b15cb3dSCy Schubert if (debug) 7272b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 7282b15cb3dSCy Schubert } 7292b15cb3dSCy Schubert 7302b15cb3dSCy Schubert /* 7312b15cb3dSCy Schubert * Write the encrypted IFF server keys to the stdout stream. 7322b15cb3dSCy Schubert */ 7332b15cb3dSCy Schubert if (pkey_iffkey != NULL && passwd2 != NULL) { 7342b15cb3dSCy Schubert DSA *dsa; 7352b15cb3dSCy Schubert 7362b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7372b15cb3dSCy Schubert "ntpkey_iffkey_%s.%u", groupname, fstamp); 7382b15cb3dSCy Schubert fprintf(stderr, "Writing IFF keys %s to stdout\n", 7392b15cb3dSCy Schubert filename); 7402b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7412b15cb3dSCy Schubert ctime(&epoch)); 742*f391d6bcSXin LI dsa = EVP_PKEY_get0_DSA(pkey_iffkey); 7432b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 7442b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey, dsa); 7452b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 7462b15cb3dSCy Schubert NULL, passwd2); 7472b15cb3dSCy Schubert fflush(stdout); 7482b15cb3dSCy Schubert if (debug) 7492b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 7502b15cb3dSCy Schubert } 7512b15cb3dSCy Schubert 7522b15cb3dSCy Schubert /* 7532b15cb3dSCy Schubert * Create new encrypted MV trusted-authority keys file if 7542b15cb3dSCy Schubert * requested; otherwise, look for existing keys file. 7552b15cb3dSCy Schubert */ 7562b15cb3dSCy Schubert if (mvkey) 7572b15cb3dSCy Schubert pkey_mvkey = gen_mvkey("mv", pkey_mvpar); 7582b15cb3dSCy Schubert if (pkey_mvkey == NULL) { 7592b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_mvta_%s", 7602b15cb3dSCy Schubert groupname); 7612b15cb3dSCy Schubert pkey_mvkey = readkey(filename, passwd1, &fstamp, 7622b15cb3dSCy Schubert pkey_mvpar); 7632b15cb3dSCy Schubert if (pkey_mvkey != NULL) { 7642b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 7652b15cb3dSCy Schubert fprintf(stderr, "Using MV keys %s\n", 7662b15cb3dSCy Schubert filename); 7672b15cb3dSCy Schubert } 7682b15cb3dSCy Schubert } 7692b15cb3dSCy Schubert 7702b15cb3dSCy Schubert /* 7712b15cb3dSCy Schubert * Write the nonencrypted MV client parameters to the stdout 7722b15cb3dSCy Schubert * stream. For the moment, we always use the client parameters 7732b15cb3dSCy Schubert * associated with client key 1. 7742b15cb3dSCy Schubert */ 7752b15cb3dSCy Schubert if (pkey_mvkey != NULL && HAVE_OPT(ID_KEY)) { 7762b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7772b15cb3dSCy Schubert "ntpkey_mvpar_%s.%u", groupname, fstamp); 7782b15cb3dSCy Schubert fprintf(stderr, "Writing MV parameters %s to stdout\n", 7792b15cb3dSCy Schubert filename); 7802b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7812b15cb3dSCy Schubert ctime(&epoch)); 7822b15cb3dSCy Schubert pkey = pkey_mvpar[2]; 7832b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 7842b15cb3dSCy Schubert NULL, NULL); 7852b15cb3dSCy Schubert fflush(stdout); 7862b15cb3dSCy Schubert if (debug) 787*f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(pkey), 0); 7882b15cb3dSCy Schubert } 7892b15cb3dSCy Schubert 7902b15cb3dSCy Schubert /* 7912b15cb3dSCy Schubert * Write the encrypted MV server keys to the stdout stream. 7922b15cb3dSCy Schubert */ 7932b15cb3dSCy Schubert if (pkey_mvkey != NULL && passwd2 != NULL) { 7942b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7952b15cb3dSCy Schubert "ntpkey_mvkey_%s.%u", groupname, fstamp); 7962b15cb3dSCy Schubert fprintf(stderr, "Writing MV keys %s to stdout\n", 7972b15cb3dSCy Schubert filename); 7982b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7992b15cb3dSCy Schubert ctime(&epoch)); 8002b15cb3dSCy Schubert pkey = pkey_mvpar[1]; 8012b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 8022b15cb3dSCy Schubert NULL, passwd2); 8032b15cb3dSCy Schubert fflush(stdout); 8042b15cb3dSCy Schubert if (debug) 805*f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(pkey), 0); 8062b15cb3dSCy Schubert } 8072b15cb3dSCy Schubert 8082b15cb3dSCy Schubert /* 8092b15cb3dSCy Schubert * Decode the digest/signature scheme and create the 8102b15cb3dSCy Schubert * certificate. Do this every time we run the program. 8112b15cb3dSCy Schubert */ 8129c2daa00SOllivier Robert ectx = EVP_get_digestbyname(scheme); 8139c2daa00SOllivier Robert if (ectx == NULL) { 8149c2daa00SOllivier Robert fprintf(stderr, 8159c2daa00SOllivier Robert "Invalid digest/signature combination %s\n", 8169c2daa00SOllivier Robert scheme); 8172b15cb3dSCy Schubert exit (-1); 8189c2daa00SOllivier Robert } 8192b15cb3dSCy Schubert x509(pkey_sign, ectx, grpkey, exten, certname); 8202b15cb3dSCy Schubert #endif /* AUTOKEY */ 8212b15cb3dSCy Schubert exit(0); 8229c2daa00SOllivier Robert } 8239c2daa00SOllivier Robert 8242b15cb3dSCy Schubert 8259c2daa00SOllivier Robert /* 8262b15cb3dSCy Schubert * Generate semi-random MD5 keys compatible with NTPv3 and NTPv4. Also, 8272b15cb3dSCy Schubert * if OpenSSL is around, generate random SHA1 keys compatible with 8282b15cb3dSCy Schubert * symmetric key cryptography. 8299c2daa00SOllivier Robert */ 8309c2daa00SOllivier Robert int 8319c2daa00SOllivier Robert gen_md5( 8322b15cb3dSCy Schubert const char *id /* file name id */ 8339c2daa00SOllivier Robert ) 8349c2daa00SOllivier Robert { 8352b15cb3dSCy Schubert u_char md5key[MD5SIZE + 1]; /* MD5 key */ 8369c2daa00SOllivier Robert FILE *str; 8379c2daa00SOllivier Robert int i, j; 8382b15cb3dSCy Schubert #ifdef OPENSSL 8392b15cb3dSCy Schubert u_char keystr[MD5SIZE]; 8402b15cb3dSCy Schubert u_char hexstr[2 * MD5SIZE + 1]; 8412b15cb3dSCy Schubert u_char hex[] = "0123456789abcdef"; 8422b15cb3dSCy Schubert #endif /* OPENSSL */ 8439c2daa00SOllivier Robert 8442b15cb3dSCy Schubert str = fheader("MD5key", id, groupname); 8459c2daa00SOllivier Robert for (i = 1; i <= MD5KEYS; i++) { 8462b15cb3dSCy Schubert for (j = 0; j < MD5SIZE; j++) { 847a25439b6SCy Schubert u_char temp; 8482b15cb3dSCy Schubert 8499c2daa00SOllivier Robert while (1) { 8502b15cb3dSCy Schubert int rc; 8512b15cb3dSCy Schubert 852a25439b6SCy Schubert rc = ntp_crypto_random_buf( 853a25439b6SCy Schubert &temp, sizeof(temp)); 8542b15cb3dSCy Schubert if (-1 == rc) { 8552b15cb3dSCy Schubert fprintf(stderr, "ntp_crypto_random_buf() failed.\n"); 8562b15cb3dSCy Schubert exit (-1); 8572b15cb3dSCy Schubert } 8589c2daa00SOllivier Robert if (temp == '#') 8599c2daa00SOllivier Robert continue; 8602b15cb3dSCy Schubert 8619c2daa00SOllivier Robert if (temp > 0x20 && temp < 0x7f) 8629c2daa00SOllivier Robert break; 8639c2daa00SOllivier Robert } 864a25439b6SCy Schubert md5key[j] = temp; 8659c2daa00SOllivier Robert } 8662b15cb3dSCy Schubert md5key[j] = '\0'; 8672b15cb3dSCy Schubert fprintf(str, "%2d MD5 %s # MD5 key\n", i, 8689c2daa00SOllivier Robert md5key); 8699c2daa00SOllivier Robert } 8702b15cb3dSCy Schubert #ifdef OPENSSL 8712b15cb3dSCy Schubert for (i = 1; i <= MD5KEYS; i++) { 8722b15cb3dSCy Schubert RAND_bytes(keystr, 20); 8732b15cb3dSCy Schubert for (j = 0; j < MD5SIZE; j++) { 8742b15cb3dSCy Schubert hexstr[2 * j] = hex[keystr[j] >> 4]; 8752b15cb3dSCy Schubert hexstr[2 * j + 1] = hex[keystr[j] & 0xf]; 8762b15cb3dSCy Schubert } 8772b15cb3dSCy Schubert hexstr[2 * MD5SIZE] = '\0'; 8782b15cb3dSCy Schubert fprintf(str, "%2d SHA1 %s # SHA1 key\n", i + MD5KEYS, 8792b15cb3dSCy Schubert hexstr); 8809c2daa00SOllivier Robert } 8819c2daa00SOllivier Robert #endif /* OPENSSL */ 8822b15cb3dSCy Schubert fclose(str); 8832b15cb3dSCy Schubert return (1); 8842b15cb3dSCy Schubert } 8859c2daa00SOllivier Robert 8869c2daa00SOllivier Robert 8872b15cb3dSCy Schubert #ifdef AUTOKEY 8882b15cb3dSCy Schubert /* 8892b15cb3dSCy Schubert * readkey - load cryptographic parameters and keys 8902b15cb3dSCy Schubert * 8912b15cb3dSCy Schubert * This routine loads a PEM-encoded file of given name and password and 8922b15cb3dSCy Schubert * extracts the filestamp from the file name. It returns a pointer to 8932b15cb3dSCy Schubert * the first key if valid, NULL if not. 8942b15cb3dSCy Schubert */ 8952b15cb3dSCy Schubert EVP_PKEY * /* public/private key pair */ 8962b15cb3dSCy Schubert readkey( 8972b15cb3dSCy Schubert char *cp, /* file name */ 8982b15cb3dSCy Schubert char *passwd, /* password */ 8992b15cb3dSCy Schubert u_int *estamp, /* file stamp */ 9002b15cb3dSCy Schubert EVP_PKEY **evpars /* parameter list pointer */ 9012b15cb3dSCy Schubert ) 9022b15cb3dSCy Schubert { 9032b15cb3dSCy Schubert FILE *str; /* file handle */ 9042b15cb3dSCy Schubert EVP_PKEY *pkey = NULL; /* public/private key */ 9052b15cb3dSCy Schubert u_int gstamp; /* filestamp */ 9062b15cb3dSCy Schubert char linkname[MAXFILENAME]; /* filestamp buffer) */ 9072b15cb3dSCy Schubert EVP_PKEY *parkey; 9082b15cb3dSCy Schubert char *ptr; 9092b15cb3dSCy Schubert int i; 9102b15cb3dSCy Schubert 9112b15cb3dSCy Schubert /* 9122b15cb3dSCy Schubert * Open the key file. 9132b15cb3dSCy Schubert */ 9142b15cb3dSCy Schubert str = fopen(cp, "r"); 9152b15cb3dSCy Schubert if (str == NULL) 9162b15cb3dSCy Schubert return (NULL); 9172b15cb3dSCy Schubert 9182b15cb3dSCy Schubert /* 9192b15cb3dSCy Schubert * Read the filestamp, which is contained in the first line. 9202b15cb3dSCy Schubert */ 9212b15cb3dSCy Schubert if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) { 9222b15cb3dSCy Schubert fprintf(stderr, "Empty key file %s\n", cp); 9232b15cb3dSCy Schubert fclose(str); 9242b15cb3dSCy Schubert return (NULL); 9252b15cb3dSCy Schubert } 9262b15cb3dSCy Schubert if ((ptr = strrchr(ptr, '.')) == NULL) { 9272b15cb3dSCy Schubert fprintf(stderr, "No filestamp found in %s\n", cp); 9282b15cb3dSCy Schubert fclose(str); 9292b15cb3dSCy Schubert return (NULL); 9302b15cb3dSCy Schubert } 9312b15cb3dSCy Schubert if (sscanf(++ptr, "%u", &gstamp) != 1) { 9322b15cb3dSCy Schubert fprintf(stderr, "Invalid filestamp found in %s\n", cp); 9332b15cb3dSCy Schubert fclose(str); 9342b15cb3dSCy Schubert return (NULL); 9352b15cb3dSCy Schubert } 9362b15cb3dSCy Schubert 9372b15cb3dSCy Schubert /* 9382b15cb3dSCy Schubert * Read and decrypt PEM-encoded private keys. The first one 9392b15cb3dSCy Schubert * found is returned. If others are expected, add them to the 9402b15cb3dSCy Schubert * parameter list. 9412b15cb3dSCy Schubert */ 9422b15cb3dSCy Schubert for (i = 0; i <= MVMAX - 1;) { 9432b15cb3dSCy Schubert parkey = PEM_read_PrivateKey(str, NULL, NULL, passwd); 9442b15cb3dSCy Schubert if (evpars != NULL) { 9452b15cb3dSCy Schubert evpars[i++] = parkey; 9462b15cb3dSCy Schubert evpars[i] = NULL; 9472b15cb3dSCy Schubert } 9482b15cb3dSCy Schubert if (parkey == NULL) 9492b15cb3dSCy Schubert break; 9502b15cb3dSCy Schubert 9512b15cb3dSCy Schubert if (pkey == NULL) 9522b15cb3dSCy Schubert pkey = parkey; 9532b15cb3dSCy Schubert if (debug) { 954*f391d6bcSXin LI if (EVP_PKEY_base_id(parkey) == EVP_PKEY_DSA) 955*f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(parkey), 9562b15cb3dSCy Schubert 0); 957*f391d6bcSXin LI else if (EVP_PKEY_base_id(parkey) == EVP_PKEY_RSA) 958*f391d6bcSXin LI RSA_print_fp(stderr, EVP_PKEY_get0_RSA(parkey), 9592b15cb3dSCy Schubert 0); 9602b15cb3dSCy Schubert } 9612b15cb3dSCy Schubert } 9622b15cb3dSCy Schubert fclose(str); 9632b15cb3dSCy Schubert if (pkey == NULL) { 9642b15cb3dSCy Schubert fprintf(stderr, "Corrupt file %s or wrong key %s\n%s\n", 9652b15cb3dSCy Schubert cp, passwd, ERR_error_string(ERR_get_error(), 9662b15cb3dSCy Schubert NULL)); 9672b15cb3dSCy Schubert exit (-1); 9682b15cb3dSCy Schubert } 9692b15cb3dSCy Schubert *estamp = gstamp; 9702b15cb3dSCy Schubert return (pkey); 9712b15cb3dSCy Schubert } 9722b15cb3dSCy Schubert 9732b15cb3dSCy Schubert 9749c2daa00SOllivier Robert /* 9759c2daa00SOllivier Robert * Generate RSA public/private key pair 9769c2daa00SOllivier Robert */ 9779c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 9789c2daa00SOllivier Robert gen_rsa( 9792b15cb3dSCy Schubert const char *id /* file name id */ 9809c2daa00SOllivier Robert ) 9819c2daa00SOllivier Robert { 9829c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 9839c2daa00SOllivier Robert RSA *rsa; /* RSA parameters and key pair */ 9849c2daa00SOllivier Robert FILE *str; 9859c2daa00SOllivier Robert 9869c2daa00SOllivier Robert fprintf(stderr, "Generating RSA keys (%d bits)...\n", modulus); 987*f391d6bcSXin LI rsa = genRsaKeyPair(modulus, _UC("RSA")); 9889c2daa00SOllivier Robert fprintf(stderr, "\n"); 9899c2daa00SOllivier Robert if (rsa == NULL) { 9909c2daa00SOllivier Robert fprintf(stderr, "RSA generate keys fails\n%s\n", 9919c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 9929c2daa00SOllivier Robert return (NULL); 9939c2daa00SOllivier Robert } 9949c2daa00SOllivier Robert 9959c2daa00SOllivier Robert /* 9969c2daa00SOllivier Robert * For signature encryption it is not necessary that the RSA 9979c2daa00SOllivier Robert * parameters be strictly groomed and once in a while the 9989c2daa00SOllivier Robert * modulus turns out to be non-prime. Just for grins, we check 9999c2daa00SOllivier Robert * the primality. 10009c2daa00SOllivier Robert */ 10019c2daa00SOllivier Robert if (!RSA_check_key(rsa)) { 10029c2daa00SOllivier Robert fprintf(stderr, "Invalid RSA key\n%s\n", 10039c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10049c2daa00SOllivier Robert RSA_free(rsa); 10059c2daa00SOllivier Robert return (NULL); 10069c2daa00SOllivier Robert } 10079c2daa00SOllivier Robert 10089c2daa00SOllivier Robert /* 10099c2daa00SOllivier Robert * Write the RSA parameters and keys as a RSA private key 10109c2daa00SOllivier Robert * encoded in PEM. 10119c2daa00SOllivier Robert */ 10122b15cb3dSCy Schubert if (strcmp(id, "sign") == 0) 10132b15cb3dSCy Schubert str = fheader("RSAsign", id, hostname); 10142b15cb3dSCy Schubert else 10152b15cb3dSCy Schubert str = fheader("RSAhost", id, hostname); 10169c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 10179c2daa00SOllivier Robert EVP_PKEY_assign_RSA(pkey, rsa); 10182b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 10192b15cb3dSCy Schubert passwd1); 10209c2daa00SOllivier Robert fclose(str); 10219c2daa00SOllivier Robert if (debug) 10222b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 10239c2daa00SOllivier Robert return (pkey); 10249c2daa00SOllivier Robert } 10259c2daa00SOllivier Robert 10269c2daa00SOllivier Robert 10279c2daa00SOllivier Robert /* 10289c2daa00SOllivier Robert * Generate DSA public/private key pair 10299c2daa00SOllivier Robert */ 10309c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 10319c2daa00SOllivier Robert gen_dsa( 10322b15cb3dSCy Schubert const char *id /* file name id */ 10339c2daa00SOllivier Robert ) 10349c2daa00SOllivier Robert { 10359c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 10369c2daa00SOllivier Robert DSA *dsa; /* DSA parameters */ 10379c2daa00SOllivier Robert FILE *str; 10389c2daa00SOllivier Robert 10399c2daa00SOllivier Robert /* 10409c2daa00SOllivier Robert * Generate DSA parameters. 10419c2daa00SOllivier Robert */ 10429c2daa00SOllivier Robert fprintf(stderr, 10439c2daa00SOllivier Robert "Generating DSA parameters (%d bits)...\n", modulus); 1044*f391d6bcSXin LI dsa = genDsaParams(modulus, _UC("DSA")); 10459c2daa00SOllivier Robert fprintf(stderr, "\n"); 10469c2daa00SOllivier Robert if (dsa == NULL) { 10479c2daa00SOllivier Robert fprintf(stderr, "DSA generate parameters fails\n%s\n", 10489c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10499c2daa00SOllivier Robert return (NULL); 10509c2daa00SOllivier Robert } 10519c2daa00SOllivier Robert 10529c2daa00SOllivier Robert /* 10539c2daa00SOllivier Robert * Generate DSA keys. 10549c2daa00SOllivier Robert */ 10559c2daa00SOllivier Robert fprintf(stderr, "Generating DSA keys (%d bits)...\n", modulus); 10569c2daa00SOllivier Robert if (!DSA_generate_key(dsa)) { 10579c2daa00SOllivier Robert fprintf(stderr, "DSA generate keys fails\n%s\n", 10589c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10599c2daa00SOllivier Robert DSA_free(dsa); 10609c2daa00SOllivier Robert return (NULL); 10619c2daa00SOllivier Robert } 10629c2daa00SOllivier Robert 10639c2daa00SOllivier Robert /* 10649c2daa00SOllivier Robert * Write the DSA parameters and keys as a DSA private key 10659c2daa00SOllivier Robert * encoded in PEM. 10669c2daa00SOllivier Robert */ 10672b15cb3dSCy Schubert str = fheader("DSAsign", id, hostname); 10689c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 10699c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 10702b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 10712b15cb3dSCy Schubert passwd1); 10729c2daa00SOllivier Robert fclose(str); 10739c2daa00SOllivier Robert if (debug) 10742b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 10759c2daa00SOllivier Robert return (pkey); 10769c2daa00SOllivier Robert } 10779c2daa00SOllivier Robert 10789c2daa00SOllivier Robert 10799c2daa00SOllivier Robert /* 10802b15cb3dSCy Schubert *********************************************************************** 10812b15cb3dSCy Schubert * * 10822b15cb3dSCy Schubert * The following routines implement the Schnorr (IFF) identity scheme * 10832b15cb3dSCy Schubert * * 10842b15cb3dSCy Schubert *********************************************************************** 10859c2daa00SOllivier Robert * 10869c2daa00SOllivier Robert * The Schnorr (IFF) identity scheme is intended for use when 10879c2daa00SOllivier Robert * certificates are generated by some other trusted certificate 10882b15cb3dSCy Schubert * authority and the certificate cannot be used to convey public 10892b15cb3dSCy Schubert * parameters. There are two kinds of files: encrypted server files that 10902b15cb3dSCy Schubert * contain private and public values and nonencrypted client files that 10912b15cb3dSCy Schubert * contain only public values. New generations of server files must be 10922b15cb3dSCy Schubert * securely transmitted to all servers of the group; client files can be 10932b15cb3dSCy Schubert * distributed by any means. The scheme is self contained and 10942b15cb3dSCy Schubert * independent of new generations of host keys, sign keys and 10952b15cb3dSCy Schubert * certificates. 10969c2daa00SOllivier Robert * 10979c2daa00SOllivier Robert * The IFF values hide in a DSA cuckoo structure which uses the same 10989c2daa00SOllivier Robert * parameters. The values are used by an identity scheme based on DSA 10999c2daa00SOllivier Robert * cryptography and described in Stimson p. 285. The p is a 512-bit 11009c2daa00SOllivier Robert * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1 11019c2daa00SOllivier Robert * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a 11022b15cb3dSCy Schubert * private random group key b (0 < b < q) and public key v = g^b, then 11032b15cb3dSCy Schubert * sends (p, q, g, b) to the servers and (p, q, g, v) to the clients. 11042b15cb3dSCy Schubert * Alice challenges Bob to confirm identity using the protocol described 11052b15cb3dSCy Schubert * below. 11062b15cb3dSCy Schubert * 11072b15cb3dSCy Schubert * How it works 11082b15cb3dSCy Schubert * 11092b15cb3dSCy Schubert * The scheme goes like this. Both Alice and Bob have the public primes 11102b15cb3dSCy Schubert * p, q and generator g. The TA gives private key b to Bob and public 11112b15cb3dSCy Schubert * key v to Alice. 11122b15cb3dSCy Schubert * 11132b15cb3dSCy Schubert * Alice rolls new random challenge r (o < r < q) and sends to Bob in 11142b15cb3dSCy Schubert * the IFF request message. Bob rolls new random k (0 < k < q), then 11152b15cb3dSCy Schubert * computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x)) 11162b15cb3dSCy Schubert * to Alice in the response message. Besides making the response 11172b15cb3dSCy Schubert * shorter, the hash makes it effectivey impossible for an intruder to 11182b15cb3dSCy Schubert * solve for b by observing a number of these messages. 11192b15cb3dSCy Schubert * 11202b15cb3dSCy Schubert * Alice receives the response and computes g^y v^r mod p. After a bit 11212b15cb3dSCy Schubert * of algebra, this simplifies to g^k. If the hash of this result 11222b15cb3dSCy Schubert * matches hash(x), Alice knows that Bob has the group key b. The signed 11232b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 11242b15cb3dSCy Schubert * previously received in his certificate. 11252b15cb3dSCy Schubert */ 11262b15cb3dSCy Schubert /* 11272b15cb3dSCy Schubert * Generate Schnorr (IFF) keys. 11289c2daa00SOllivier Robert */ 11299c2daa00SOllivier Robert EVP_PKEY * /* DSA cuckoo nest */ 11302b15cb3dSCy Schubert gen_iffkey( 11312b15cb3dSCy Schubert const char *id /* file name id */ 11329c2daa00SOllivier Robert ) 11339c2daa00SOllivier Robert { 11349c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 11359c2daa00SOllivier Robert DSA *dsa; /* DSA parameters */ 11369c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 11379c2daa00SOllivier Robert BIGNUM *b, *r, *k, *u, *v, *w; /* BN temp */ 11389c2daa00SOllivier Robert FILE *str; 11399c2daa00SOllivier Robert u_int temp; 1140*f391d6bcSXin LI const BIGNUM *p, *q, *g; 1141*f391d6bcSXin LI BIGNUM *pub_key, *priv_key; 11429c2daa00SOllivier Robert 11439c2daa00SOllivier Robert /* 11449c2daa00SOllivier Robert * Generate DSA parameters for use as IFF parameters. 11459c2daa00SOllivier Robert */ 11462b15cb3dSCy Schubert fprintf(stderr, "Generating IFF keys (%d bits)...\n", 11472b15cb3dSCy Schubert modulus2); 1148*f391d6bcSXin LI dsa = genDsaParams(modulus2, _UC("IFF")); 11499c2daa00SOllivier Robert fprintf(stderr, "\n"); 11509c2daa00SOllivier Robert if (dsa == NULL) { 11519c2daa00SOllivier Robert fprintf(stderr, "DSA generate parameters fails\n%s\n", 11529c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 1153*f391d6bcSXin LI return (NULL); 11549c2daa00SOllivier Robert } 1155*f391d6bcSXin LI DSA_get0_pqg(dsa, &p, &q, &g); 11569c2daa00SOllivier Robert 11579c2daa00SOllivier Robert /* 11589c2daa00SOllivier Robert * Generate the private and public keys. The DSA parameters and 11592b15cb3dSCy Schubert * private key are distributed to the servers, while all except 11602b15cb3dSCy Schubert * the private key are distributed to the clients. 11619c2daa00SOllivier Robert */ 11629c2daa00SOllivier Robert b = BN_new(); r = BN_new(); k = BN_new(); 11639c2daa00SOllivier Robert u = BN_new(); v = BN_new(); w = BN_new(); ctx = BN_CTX_new(); 1164*f391d6bcSXin LI BN_rand(b, BN_num_bits(q), -1, 0); /* a */ 1165*f391d6bcSXin LI BN_mod(b, b, q, ctx); 1166*f391d6bcSXin LI BN_sub(v, q, b); 1167*f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); /* g^(q - b) mod p */ 1168*f391d6bcSXin LI BN_mod_exp(u, g, b, p, ctx); /* g^b mod p */ 1169*f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 11709c2daa00SOllivier Robert temp = BN_is_one(u); 11719c2daa00SOllivier Robert fprintf(stderr, 11729c2daa00SOllivier Robert "Confirm g^(q - b) g^b = 1 mod p: %s\n", temp == 1 ? 11739c2daa00SOllivier Robert "yes" : "no"); 11749c2daa00SOllivier Robert if (!temp) { 11759c2daa00SOllivier Robert BN_free(b); BN_free(r); BN_free(k); 11769c2daa00SOllivier Robert BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 11779c2daa00SOllivier Robert return (NULL); 11789c2daa00SOllivier Robert } 1179*f391d6bcSXin LI pub_key = BN_dup(v); 1180*f391d6bcSXin LI priv_key = BN_dup(b); 1181*f391d6bcSXin LI DSA_set0_key(dsa, pub_key, priv_key); 11829c2daa00SOllivier Robert 11839c2daa00SOllivier Robert /* 11849c2daa00SOllivier Robert * Here is a trial round of the protocol. First, Alice rolls 11852b15cb3dSCy Schubert * random nonce r mod q and sends it to Bob. She needs only 11862b15cb3dSCy Schubert * q from parameters. 11879c2daa00SOllivier Robert */ 1188*f391d6bcSXin LI BN_rand(r, BN_num_bits(q), -1, 0); /* r */ 1189*f391d6bcSXin LI BN_mod(r, r, q, ctx); 11909c2daa00SOllivier Robert 11919c2daa00SOllivier Robert /* 11922b15cb3dSCy Schubert * Bob rolls random nonce k mod q, computes y = k + b r mod q 11939c2daa00SOllivier Robert * and x = g^k mod p, then sends (y, x) to Alice. He needs 11942b15cb3dSCy Schubert * p, q and b from parameters and r from Alice. 11959c2daa00SOllivier Robert */ 1196*f391d6bcSXin LI BN_rand(k, BN_num_bits(q), -1, 0); /* k, 0 < k < q */ 1197*f391d6bcSXin LI BN_mod(k, k, q, ctx); 1198*f391d6bcSXin LI BN_mod_mul(v, priv_key, r, q, ctx); /* b r mod q */ 11999c2daa00SOllivier Robert BN_add(v, v, k); 1200*f391d6bcSXin LI BN_mod(v, v, q, ctx); /* y = k + b r mod q */ 1201*f391d6bcSXin LI BN_mod_exp(u, g, k, p, ctx); /* x = g^k mod p */ 12029c2daa00SOllivier Robert 12039c2daa00SOllivier Robert /* 12042b15cb3dSCy Schubert * Alice verifies x = g^y v^r to confirm that Bob has group key 12052b15cb3dSCy Schubert * b. She needs p, q, g from parameters, (y, x) from Bob and the 12062b15cb3dSCy Schubert * original r. We omit the detail here thatt only the hash of y 12072b15cb3dSCy Schubert * is sent. 12089c2daa00SOllivier Robert */ 1209*f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); /* g^y mod p */ 1210*f391d6bcSXin LI BN_mod_exp(w, pub_key, r, p, ctx); /* v^r */ 1211*f391d6bcSXin LI BN_mod_mul(v, w, v, p, ctx); /* product mod p */ 12129c2daa00SOllivier Robert temp = BN_cmp(u, v); 12139c2daa00SOllivier Robert fprintf(stderr, 12149c2daa00SOllivier Robert "Confirm g^k = g^(k + b r) g^(q - b) r: %s\n", temp == 12159c2daa00SOllivier Robert 0 ? "yes" : "no"); 12169c2daa00SOllivier Robert BN_free(b); BN_free(r); BN_free(k); 12179c2daa00SOllivier Robert BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 12189c2daa00SOllivier Robert if (temp != 0) { 12199c2daa00SOllivier Robert DSA_free(dsa); 12209c2daa00SOllivier Robert return (NULL); 12219c2daa00SOllivier Robert } 12229c2daa00SOllivier Robert 12239c2daa00SOllivier Robert /* 12242b15cb3dSCy Schubert * Write the IFF keys as an encrypted DSA private key encoded in 12252b15cb3dSCy Schubert * PEM. 12269c2daa00SOllivier Robert * 12279c2daa00SOllivier Robert * p modulus p 12289c2daa00SOllivier Robert * q modulus q 12299c2daa00SOllivier Robert * g generator g 12309c2daa00SOllivier Robert * priv_key b 12319c2daa00SOllivier Robert * public_key v 12322b15cb3dSCy Schubert * kinv not used 12332b15cb3dSCy Schubert * r not used 12349c2daa00SOllivier Robert */ 12352b15cb3dSCy Schubert str = fheader("IFFkey", id, groupname); 12369c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 12379c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 12382b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 12392b15cb3dSCy Schubert passwd1); 12409c2daa00SOllivier Robert fclose(str); 12419c2daa00SOllivier Robert if (debug) 12422b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 12439c2daa00SOllivier Robert return (pkey); 12449c2daa00SOllivier Robert } 12459c2daa00SOllivier Robert 12469c2daa00SOllivier Robert 12479c2daa00SOllivier Robert /* 12482b15cb3dSCy Schubert *********************************************************************** 12492b15cb3dSCy Schubert * * 12502b15cb3dSCy Schubert * The following routines implement the Guillou-Quisquater (GQ) * 12512b15cb3dSCy Schubert * identity scheme * 12522b15cb3dSCy Schubert * * 12532b15cb3dSCy Schubert *********************************************************************** 12549c2daa00SOllivier Robert * 12559c2daa00SOllivier Robert * The Guillou-Quisquater (GQ) identity scheme is intended for use when 12562b15cb3dSCy Schubert * the certificate can be used to convey public parameters. The scheme 12572b15cb3dSCy Schubert * uses a X509v3 certificate extension field do convey the public key of 12582b15cb3dSCy Schubert * a private key known only to servers. There are two kinds of files: 12592b15cb3dSCy Schubert * encrypted server files that contain private and public values and 12602b15cb3dSCy Schubert * nonencrypted client files that contain only public values. New 12612b15cb3dSCy Schubert * generations of server files must be securely transmitted to all 12622b15cb3dSCy Schubert * servers of the group; client files can be distributed by any means. 12632b15cb3dSCy Schubert * The scheme is self contained and independent of new generations of 12642b15cb3dSCy Schubert * host keys and sign keys. The scheme is self contained and independent 12652b15cb3dSCy Schubert * of new generations of host keys and sign keys. 12669c2daa00SOllivier Robert * 12679c2daa00SOllivier Robert * The GQ parameters hide in a RSA cuckoo structure which uses the same 12689c2daa00SOllivier Robert * parameters. The values are used by an identity scheme based on RSA 12699c2daa00SOllivier Robert * cryptography and described in Stimson p. 300 (with errors). The 512- 12709c2daa00SOllivier Robert * bit public modulus is n = p q, where p and q are secret large primes. 12719c2daa00SOllivier Robert * The TA rolls private random group key b as RSA exponent. These values 12729c2daa00SOllivier Robert * are known to all group members. 12739c2daa00SOllivier Robert * 12742b15cb3dSCy Schubert * When rolling new certificates, a server recomputes the private and 12759c2daa00SOllivier Robert * public keys. The private key u is a random roll, while the public key 12769c2daa00SOllivier Robert * is the inverse obscured by the group key v = (u^-1)^b. These values 12779c2daa00SOllivier Robert * replace the private and public keys normally generated by the RSA 12789c2daa00SOllivier Robert * scheme. Alice challenges Bob to confirm identity using the protocol 12799c2daa00SOllivier Robert * described below. 12809c2daa00SOllivier Robert * 12812b15cb3dSCy Schubert * How it works 12822b15cb3dSCy Schubert * 12832b15cb3dSCy Schubert * The scheme goes like this. Both Alice and Bob have the same modulus n 12842b15cb3dSCy Schubert * and some random b as the group key. These values are computed and 12852b15cb3dSCy Schubert * distributed in advance via secret means, although only the group key 12862b15cb3dSCy Schubert * b is truly secret. Each has a private random private key u and public 12872b15cb3dSCy Schubert * key (u^-1)^b, although not necessarily the same ones. Bob and Alice 12882b15cb3dSCy Schubert * can regenerate the key pair from time to time without affecting 12892b15cb3dSCy Schubert * operations. The public key is conveyed on the certificate in an 12902b15cb3dSCy Schubert * extension field; the private key is never revealed. 12912b15cb3dSCy Schubert * 12922b15cb3dSCy Schubert * Alice rolls new random challenge r and sends to Bob in the GQ 12932b15cb3dSCy Schubert * request message. Bob rolls new random k, then computes y = k u^r mod 12942b15cb3dSCy Schubert * n and x = k^b mod n and sends (y, hash(x)) to Alice in the response 12952b15cb3dSCy Schubert * message. Besides making the response shorter, the hash makes it 12962b15cb3dSCy Schubert * effectivey impossible for an intruder to solve for b by observing 12972b15cb3dSCy Schubert * a number of these messages. 12982b15cb3dSCy Schubert * 12992b15cb3dSCy Schubert * Alice receives the response and computes y^b v^r mod n. After a bit 13002b15cb3dSCy Schubert * of algebra, this simplifies to k^b. If the hash of this result 13012b15cb3dSCy Schubert * matches hash(x), Alice knows that Bob has the group key b. The signed 13022b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 13032b15cb3dSCy Schubert * previously received in his certificate. 13049c2daa00SOllivier Robert */ 13059c2daa00SOllivier Robert /* 13062b15cb3dSCy Schubert * Generate Guillou-Quisquater (GQ) parameters file. 13079c2daa00SOllivier Robert */ 13089c2daa00SOllivier Robert EVP_PKEY * /* RSA cuckoo nest */ 13099c2daa00SOllivier Robert gen_gqkey( 13102b15cb3dSCy Schubert const char *id /* file name id */ 13119c2daa00SOllivier Robert ) 13129c2daa00SOllivier Robert { 13139c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 13149c2daa00SOllivier Robert RSA *rsa; /* RSA parameters */ 13159c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 13169c2daa00SOllivier Robert BIGNUM *u, *v, *g, *k, *r, *y; /* BN temps */ 13179c2daa00SOllivier Robert FILE *str; 13189c2daa00SOllivier Robert u_int temp; 1319*f391d6bcSXin LI BIGNUM *b; 1320*f391d6bcSXin LI const BIGNUM *n; 13219c2daa00SOllivier Robert 13229c2daa00SOllivier Robert /* 13232b15cb3dSCy Schubert * Generate RSA parameters for use as GQ parameters. 13249c2daa00SOllivier Robert */ 13252b15cb3dSCy Schubert fprintf(stderr, 13262b15cb3dSCy Schubert "Generating GQ parameters (%d bits)...\n", 13272b15cb3dSCy Schubert modulus2); 1328*f391d6bcSXin LI rsa = genRsaKeyPair(modulus2, _UC("GQ")); 13292b15cb3dSCy Schubert fprintf(stderr, "\n"); 13302b15cb3dSCy Schubert if (rsa == NULL) { 13312b15cb3dSCy Schubert fprintf(stderr, "RSA generate keys fails\n%s\n", 13322b15cb3dSCy Schubert ERR_error_string(ERR_get_error(), NULL)); 13332b15cb3dSCy Schubert return (NULL); 13342b15cb3dSCy Schubert } 1335*f391d6bcSXin LI RSA_get0_key(rsa, &n, NULL, NULL); 13362b15cb3dSCy Schubert u = BN_new(); v = BN_new(); g = BN_new(); 13372b15cb3dSCy Schubert k = BN_new(); r = BN_new(); y = BN_new(); 1338*f391d6bcSXin LI b = BN_new(); 13392b15cb3dSCy Schubert 13402b15cb3dSCy Schubert /* 13412b15cb3dSCy Schubert * Generate the group key b, which is saved in the e member of 13422b15cb3dSCy Schubert * the RSA structure. The group key is transmitted to each group 13432b15cb3dSCy Schubert * member encrypted by the member private key. 13442b15cb3dSCy Schubert */ 13452b15cb3dSCy Schubert ctx = BN_CTX_new(); 1346*f391d6bcSXin LI BN_rand(b, BN_num_bits(n), -1, 0); /* b */ 1347*f391d6bcSXin LI BN_mod(b, b, n, ctx); 13489c2daa00SOllivier Robert 13499c2daa00SOllivier Robert /* 13509c2daa00SOllivier Robert * When generating his certificate, Bob rolls random private key 13512b15cb3dSCy Schubert * u, then computes inverse v = u^-1. 13529c2daa00SOllivier Robert */ 1353*f391d6bcSXin LI BN_rand(u, BN_num_bits(n), -1, 0); /* u */ 1354*f391d6bcSXin LI BN_mod(u, u, n, ctx); 1355*f391d6bcSXin LI BN_mod_inverse(v, u, n, ctx); /* u^-1 mod n */ 1356*f391d6bcSXin LI BN_mod_mul(k, v, u, n, ctx); 13579c2daa00SOllivier Robert 13589c2daa00SOllivier Robert /* 13599c2daa00SOllivier Robert * Bob computes public key v = (u^-1)^b, which is saved in an 13609c2daa00SOllivier Robert * extension field on his certificate. We check that u^b v = 13619c2daa00SOllivier Robert * 1 mod n. 13629c2daa00SOllivier Robert */ 1363*f391d6bcSXin LI BN_mod_exp(v, v, b, n, ctx); 1364*f391d6bcSXin LI BN_mod_exp(g, u, b, n, ctx); /* u^b */ 1365*f391d6bcSXin LI BN_mod_mul(g, g, v, n, ctx); /* u^b (u^-1)^b */ 13669c2daa00SOllivier Robert temp = BN_is_one(g); 13679c2daa00SOllivier Robert fprintf(stderr, 13689c2daa00SOllivier Robert "Confirm u^b (u^-1)^b = 1 mod n: %s\n", temp ? "yes" : 13699c2daa00SOllivier Robert "no"); 13709c2daa00SOllivier Robert if (!temp) { 13719c2daa00SOllivier Robert BN_free(u); BN_free(v); 13729c2daa00SOllivier Robert BN_free(g); BN_free(k); BN_free(r); BN_free(y); 13739c2daa00SOllivier Robert BN_CTX_free(ctx); 13749c2daa00SOllivier Robert RSA_free(rsa); 13759c2daa00SOllivier Robert return (NULL); 13769c2daa00SOllivier Robert } 1377*f391d6bcSXin LI /* setting 'u' and 'v' into a RSA object takes over ownership. 1378*f391d6bcSXin LI * Since we use these values again, we have to pass in dupes, 1379*f391d6bcSXin LI * or we'll corrupt the program! 1380*f391d6bcSXin LI */ 1381*f391d6bcSXin LI RSA_set0_factors(rsa, BN_dup(u), BN_dup(v)); 13829c2daa00SOllivier Robert 13839c2daa00SOllivier Robert /* 13849c2daa00SOllivier Robert * Here is a trial run of the protocol. First, Alice rolls 13852b15cb3dSCy Schubert * random nonce r mod n and sends it to Bob. She needs only n 13862b15cb3dSCy Schubert * from parameters. 13879c2daa00SOllivier Robert */ 1388*f391d6bcSXin LI BN_rand(r, BN_num_bits(n), -1, 0); /* r */ 1389*f391d6bcSXin LI BN_mod(r, r, n, ctx); 13909c2daa00SOllivier Robert 13919c2daa00SOllivier Robert /* 13922b15cb3dSCy Schubert * Bob rolls random nonce k mod n, computes y = k u^r mod n and 13932b15cb3dSCy Schubert * g = k^b mod n, then sends (y, g) to Alice. He needs n, u, b 13942b15cb3dSCy Schubert * from parameters and r from Alice. 13959c2daa00SOllivier Robert */ 1396*f391d6bcSXin LI BN_rand(k, BN_num_bits(n), -1, 0); /* k */ 1397*f391d6bcSXin LI BN_mod(k, k, n, ctx); 1398*f391d6bcSXin LI BN_mod_exp(y, u, r, n, ctx); /* u^r mod n */ 1399*f391d6bcSXin LI BN_mod_mul(y, k, y, n, ctx); /* y = k u^r mod n */ 1400*f391d6bcSXin LI BN_mod_exp(g, k, b, n, ctx); /* g = k^b mod n */ 14019c2daa00SOllivier Robert 14029c2daa00SOllivier Robert /* 14032b15cb3dSCy Schubert * Alice verifies g = v^r y^b mod n to confirm that Bob has 14042b15cb3dSCy Schubert * private key u. She needs n, g from parameters, public key v = 14052b15cb3dSCy Schubert * (u^-1)^b from the certificate, (y, g) from Bob and the 14062b15cb3dSCy Schubert * original r. We omit the detaul here that only the hash of g 14072b15cb3dSCy Schubert * is sent. 14089c2daa00SOllivier Robert */ 1409*f391d6bcSXin LI BN_mod_exp(v, v, r, n, ctx); /* v^r mod n */ 1410*f391d6bcSXin LI BN_mod_exp(y, y, b, n, ctx); /* y^b mod n */ 1411*f391d6bcSXin LI BN_mod_mul(y, v, y, n, ctx); /* v^r y^b mod n */ 14129c2daa00SOllivier Robert temp = BN_cmp(y, g); 14139c2daa00SOllivier Robert fprintf(stderr, "Confirm g^k = v^r y^b mod n: %s\n", temp == 0 ? 14149c2daa00SOllivier Robert "yes" : "no"); 14159c2daa00SOllivier Robert BN_CTX_free(ctx); BN_free(u); BN_free(v); 14169c2daa00SOllivier Robert BN_free(g); BN_free(k); BN_free(r); BN_free(y); 14179c2daa00SOllivier Robert if (temp != 0) { 14189c2daa00SOllivier Robert RSA_free(rsa); 14199c2daa00SOllivier Robert return (NULL); 14209c2daa00SOllivier Robert } 14219c2daa00SOllivier Robert 14229c2daa00SOllivier Robert /* 14232b15cb3dSCy Schubert * Write the GQ parameter file as an encrypted RSA private key 14242b15cb3dSCy Schubert * encoded in PEM. 14259c2daa00SOllivier Robert * 14269c2daa00SOllivier Robert * n modulus n 14279c2daa00SOllivier Robert * e group key b 14282b15cb3dSCy Schubert * d not used 14299c2daa00SOllivier Robert * p private key u 14309c2daa00SOllivier Robert * q public key (u^-1)^b 14312b15cb3dSCy Schubert * dmp1 not used 14322b15cb3dSCy Schubert * dmq1 not used 14332b15cb3dSCy Schubert * iqmp not used 14349c2daa00SOllivier Robert */ 1435*f391d6bcSXin LI RSA_set0_key(rsa, NULL, b, BN_dup(BN_value_one())); 1436*f391d6bcSXin LI RSA_set0_crt_params(rsa, BN_dup(BN_value_one()), BN_dup(BN_value_one()), 1437*f391d6bcSXin LI BN_dup(BN_value_one())); 14382b15cb3dSCy Schubert str = fheader("GQkey", id, groupname); 14399c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 14409c2daa00SOllivier Robert EVP_PKEY_assign_RSA(pkey, rsa); 14412b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 14422b15cb3dSCy Schubert passwd1); 14439c2daa00SOllivier Robert fclose(str); 14449c2daa00SOllivier Robert if (debug) 14452b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 14469c2daa00SOllivier Robert return (pkey); 14479c2daa00SOllivier Robert } 14489c2daa00SOllivier Robert 14499c2daa00SOllivier Robert 14509c2daa00SOllivier Robert /* 14512b15cb3dSCy Schubert *********************************************************************** 14522b15cb3dSCy Schubert * * 14532b15cb3dSCy Schubert * The following routines implement the Mu-Varadharajan (MV) identity * 14542b15cb3dSCy Schubert * scheme * 14552b15cb3dSCy Schubert * * 14562b15cb3dSCy Schubert *********************************************************************** 14579c2daa00SOllivier Robert * 14582b15cb3dSCy Schubert * The Mu-Varadharajan (MV) cryptosystem was originally intended when 14592b15cb3dSCy Schubert * servers broadcast messages to clients, but clients never send 14602b15cb3dSCy Schubert * messages to servers. There is one encryption key for the server and a 14612b15cb3dSCy Schubert * separate decryption key for each client. It operated something like a 14629c2daa00SOllivier Robert * pay-per-view satellite broadcasting system where the session key is 14639c2daa00SOllivier Robert * encrypted by the broadcaster and the decryption keys are held in a 14642b15cb3dSCy Schubert * tamperproof set-top box. 14659c2daa00SOllivier Robert * 14669c2daa00SOllivier Robert * The MV parameters and private encryption key hide in a DSA cuckoo 14679c2daa00SOllivier Robert * structure which uses the same parameters, but generated in a 14689c2daa00SOllivier Robert * different way. The values are used in an encryption scheme similar to 14699c2daa00SOllivier Robert * El Gamal cryptography and a polynomial formed from the expansion of 14709c2daa00SOllivier Robert * product terms (x - x[j]), as described in Mu, Y., and V. 14719c2daa00SOllivier Robert * Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001, 14729c2daa00SOllivier Robert * 223-231. The paper has significant errors and serious omissions. 14739c2daa00SOllivier Robert * 14742b15cb3dSCy Schubert * Let q be the product of n distinct primes s1[j] (j = 1...n), where 14752b15cb3dSCy Schubert * each s1[j] has m significant bits. Let p be a prime p = 2 * q + 1, so 14762b15cb3dSCy Schubert * that q and each s1[j] divide p - 1 and p has M = n * m + 1 14779c2daa00SOllivier Robert * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1) 14789c2daa00SOllivier Robert * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then 14799c2daa00SOllivier Robert * project into Zp* as exponents of g. Sometimes we have to compute an 14809c2daa00SOllivier Robert * inverse b^-1 of random b in Zq, but for that purpose we require 14819c2daa00SOllivier Robert * gcd(b, q) = 1. We expect M to be in the 500-bit range and n 14822b15cb3dSCy Schubert * relatively small, like 30. These are the parameters of the scheme and 14832b15cb3dSCy Schubert * they are expensive to compute. 14849c2daa00SOllivier Robert * 14859c2daa00SOllivier Robert * We set up an instance of the scheme as follows. A set of random 14869c2daa00SOllivier Robert * values x[j] mod q (j = 1...n), are generated as the zeros of a 14879c2daa00SOllivier Robert * polynomial of order n. The product terms (x - x[j]) are expanded to 14889c2daa00SOllivier Robert * form coefficients a[i] mod q (i = 0...n) in powers of x. These are 14899c2daa00SOllivier Robert * used as exponents of the generator g mod p to generate the private 14909c2daa00SOllivier Robert * encryption key A. The pair (gbar, ghat) of public server keys and the 14919c2daa00SOllivier Robert * pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used 14929c2daa00SOllivier Robert * to construct the decryption keys. The devil is in the details. 14939c2daa00SOllivier Robert * 14942b15cb3dSCy Schubert * This routine generates a private server encryption file including the 14952b15cb3dSCy Schubert * private encryption key E and partial decryption keys gbar and ghat. 14962b15cb3dSCy Schubert * It then generates public client decryption files including the public 14972b15cb3dSCy Schubert * keys xbar[j] and xhat[j] for each client j. The partial decryption 14982b15cb3dSCy Schubert * files are used to compute the inverse of E. These values are suitably 14992b15cb3dSCy Schubert * blinded so secrets are not revealed. 15009c2daa00SOllivier Robert * 15019c2daa00SOllivier Robert * The distinguishing characteristic of this scheme is the capability to 15029c2daa00SOllivier Robert * revoke keys. Included in the calculation of E, gbar and ghat is the 15032b15cb3dSCy Schubert * product s = prod(s1[j]) (j = 1...n) above. If the factor s1[j] is 15049c2daa00SOllivier Robert * subsequently removed from the product and E, gbar and ghat 15059c2daa00SOllivier Robert * recomputed, the jth client will no longer be able to compute E^-1 and 15062b15cb3dSCy Schubert * thus unable to decrypt the messageblock. 15072b15cb3dSCy Schubert * 15082b15cb3dSCy Schubert * How it works 15092b15cb3dSCy Schubert * 15102b15cb3dSCy Schubert * The scheme goes like this. Bob has the server values (p, E, q, 15112b15cb3dSCy Schubert * gbar, ghat) and Alice has the client values (p, xbar, xhat). 15122b15cb3dSCy Schubert * 15132b15cb3dSCy Schubert * Alice rolls new random nonce r mod p and sends to Bob in the MV 15142b15cb3dSCy Schubert * request message. Bob rolls random nonce k mod q, encrypts y = r E^k 15152b15cb3dSCy Schubert * mod p and sends (y, gbar^k, ghat^k) to Alice. 15162b15cb3dSCy Schubert * 15172b15cb3dSCy Schubert * Alice receives the response and computes the inverse (E^k)^-1 from 15182b15cb3dSCy Schubert * the partial decryption keys gbar^k, ghat^k, xbar and xhat. She then 15192b15cb3dSCy Schubert * decrypts y and verifies it matches the original r. The signed 15202b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 15212b15cb3dSCy Schubert * previously received in his certificate. 15229c2daa00SOllivier Robert */ 15239c2daa00SOllivier Robert EVP_PKEY * /* DSA cuckoo nest */ 15242b15cb3dSCy Schubert gen_mvkey( 15252b15cb3dSCy Schubert const char *id, /* file name id */ 15262b15cb3dSCy Schubert EVP_PKEY **evpars /* parameter list pointer */ 15279c2daa00SOllivier Robert ) 15289c2daa00SOllivier Robert { 15292b15cb3dSCy Schubert EVP_PKEY *pkey, *pkey1; /* private keys */ 15302b15cb3dSCy Schubert DSA *dsa, *dsa2, *sdsa; /* DSA parameters */ 15319c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 15322b15cb3dSCy Schubert BIGNUM *a[MVMAX]; /* polynomial coefficient vector */ 1533*f391d6bcSXin LI BIGNUM *gs[MVMAX]; /* public key vector */ 15342b15cb3dSCy Schubert BIGNUM *s1[MVMAX]; /* private enabling keys */ 15352b15cb3dSCy Schubert BIGNUM *x[MVMAX]; /* polynomial zeros vector */ 15362b15cb3dSCy Schubert BIGNUM *xbar[MVMAX], *xhat[MVMAX]; /* private keys vector */ 15379c2daa00SOllivier Robert BIGNUM *b; /* group key */ 15389c2daa00SOllivier Robert BIGNUM *b1; /* inverse group key */ 15392b15cb3dSCy Schubert BIGNUM *s; /* enabling key */ 15409c2daa00SOllivier Robert BIGNUM *biga; /* master encryption key */ 15419c2daa00SOllivier Robert BIGNUM *bige; /* session encryption key */ 15429c2daa00SOllivier Robert BIGNUM *gbar, *ghat; /* public key */ 15439c2daa00SOllivier Robert BIGNUM *u, *v, *w; /* BN scratch */ 1544*f391d6bcSXin LI BIGNUM *p, *q, *g, *priv_key, *pub_key; 15459c2daa00SOllivier Robert int i, j, n; 15469c2daa00SOllivier Robert FILE *str; 15479c2daa00SOllivier Robert u_int temp; 15489c2daa00SOllivier Robert 15499c2daa00SOllivier Robert /* 15509c2daa00SOllivier Robert * Generate MV parameters. 15519c2daa00SOllivier Robert * 15529c2daa00SOllivier Robert * The object is to generate a multiplicative group Zp* modulo a 15539c2daa00SOllivier Robert * prime p and a subset Zq mod q, where q is the product of n 15542b15cb3dSCy Schubert * distinct primes s1[j] (j = 1...n) and q divides p - 1. We 15552b15cb3dSCy Schubert * first generate n m-bit primes, where the product n m is in 15562b15cb3dSCy Schubert * the order of 512 bits. One or more of these may have to be 15572b15cb3dSCy Schubert * replaced later. As a practical matter, it is tough to find 15582b15cb3dSCy Schubert * more than 31 distinct primes for 512 bits or 61 primes for 15592b15cb3dSCy Schubert * 1024 bits. The latter can take several hundred iterations 15609c2daa00SOllivier Robert * and several minutes on a Sun Blade 1000. 15619c2daa00SOllivier Robert */ 15629c2daa00SOllivier Robert n = nkeys; 15639c2daa00SOllivier Robert fprintf(stderr, 15649c2daa00SOllivier Robert "Generating MV parameters for %d keys (%d bits)...\n", n, 15652b15cb3dSCy Schubert modulus2 / n); 15669c2daa00SOllivier Robert ctx = BN_CTX_new(); u = BN_new(); v = BN_new(); w = BN_new(); 15679c2daa00SOllivier Robert b = BN_new(); b1 = BN_new(); 15685e91a9b7SOllivier Robert dsa = DSA_new(); 1569*f391d6bcSXin LI p = BN_new(); q = BN_new(); g = BN_new(); 1570*f391d6bcSXin LI priv_key = BN_new(); pub_key = BN_new(); 15719c2daa00SOllivier Robert temp = 0; 15729c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 15732b15cb3dSCy Schubert s1[j] = BN_new(); 15749c2daa00SOllivier Robert while (1) { 1575*f391d6bcSXin LI BN_generate_prime_ex(s1[j], modulus2 / n, 0, 15769c2daa00SOllivier Robert NULL, NULL, NULL); 15779c2daa00SOllivier Robert for (i = 1; i < j; i++) { 15789c2daa00SOllivier Robert if (BN_cmp(s1[i], s1[j]) == 0) 15799c2daa00SOllivier Robert break; 15809c2daa00SOllivier Robert } 15819c2daa00SOllivier Robert if (i == j) 15829c2daa00SOllivier Robert break; 15839c2daa00SOllivier Robert temp++; 15849c2daa00SOllivier Robert } 15859c2daa00SOllivier Robert } 15862b15cb3dSCy Schubert fprintf(stderr, "Birthday keys regenerated %d\n", temp); 15879c2daa00SOllivier Robert 15889c2daa00SOllivier Robert /* 15899c2daa00SOllivier Robert * Compute the modulus q as the product of the primes. Compute 15909c2daa00SOllivier Robert * the modulus p as 2 * q + 1 and test p for primality. If p 15919c2daa00SOllivier Robert * is composite, replace one of the primes with a new distinct 15929c2daa00SOllivier Robert * one and try again. Note that q will hardly be a secret since 15932b15cb3dSCy Schubert * we have to reveal p to servers, but not clients. However, 15949c2daa00SOllivier Robert * factoring q to find the primes should be adequately hard, as 15959c2daa00SOllivier Robert * this is the same problem considered hard in RSA. Question: is 15969c2daa00SOllivier Robert * it as hard to find n small prime factors totalling n bits as 15979c2daa00SOllivier Robert * it is to find two large prime factors totalling n bits? 15989c2daa00SOllivier Robert * Remember, the bad guy doesn't know n. 15999c2daa00SOllivier Robert */ 16009c2daa00SOllivier Robert temp = 0; 16019c2daa00SOllivier Robert while (1) { 1602*f391d6bcSXin LI BN_one(q); 16039c2daa00SOllivier Robert for (j = 1; j <= n; j++) 1604*f391d6bcSXin LI BN_mul(q, q, s1[j], ctx); 1605*f391d6bcSXin LI BN_copy(p, q); 1606*f391d6bcSXin LI BN_add(p, p, p); 1607*f391d6bcSXin LI BN_add_word(p, 1); 1608*f391d6bcSXin LI if (BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) 16099c2daa00SOllivier Robert break; 16109c2daa00SOllivier Robert 16112b15cb3dSCy Schubert temp++; 16129c2daa00SOllivier Robert j = temp % n + 1; 16139c2daa00SOllivier Robert while (1) { 1614*f391d6bcSXin LI BN_generate_prime_ex(u, modulus2 / n, 0, 1615*f391d6bcSXin LI NULL, NULL, NULL); 16169c2daa00SOllivier Robert for (i = 1; i <= n; i++) { 16179c2daa00SOllivier Robert if (BN_cmp(u, s1[i]) == 0) 16189c2daa00SOllivier Robert break; 16199c2daa00SOllivier Robert } 16209c2daa00SOllivier Robert if (i > n) 16219c2daa00SOllivier Robert break; 16229c2daa00SOllivier Robert } 16239c2daa00SOllivier Robert BN_copy(s1[j], u); 16249c2daa00SOllivier Robert } 16252b15cb3dSCy Schubert fprintf(stderr, "Defective keys regenerated %d\n", temp); 16269c2daa00SOllivier Robert 16279c2daa00SOllivier Robert /* 16289c2daa00SOllivier Robert * Compute the generator g using a random roll such that 16299c2daa00SOllivier Robert * gcd(g, p - 1) = 1 and g^q = 1. This is a generator of p, not 16302b15cb3dSCy Schubert * q. This may take several iterations. 16319c2daa00SOllivier Robert */ 1632*f391d6bcSXin LI BN_copy(v, p); 16339c2daa00SOllivier Robert BN_sub_word(v, 1); 16349c2daa00SOllivier Robert while (1) { 1635*f391d6bcSXin LI BN_rand(g, BN_num_bits(p) - 1, 0, 0); 1636*f391d6bcSXin LI BN_mod(g, g, p, ctx); 1637*f391d6bcSXin LI BN_gcd(u, g, v, ctx); 16389c2daa00SOllivier Robert if (!BN_is_one(u)) 16399c2daa00SOllivier Robert continue; 16409c2daa00SOllivier Robert 1641*f391d6bcSXin LI BN_mod_exp(u, g, q, p, ctx); 16429c2daa00SOllivier Robert if (BN_is_one(u)) 16439c2daa00SOllivier Robert break; 16449c2daa00SOllivier Robert } 16459c2daa00SOllivier Robert 1646*f391d6bcSXin LI DSA_set0_pqg(dsa, p, q, g); 1647*f391d6bcSXin LI 16489c2daa00SOllivier Robert /* 16499c2daa00SOllivier Robert * Setup is now complete. Roll random polynomial roots x[j] 16502b15cb3dSCy Schubert * (j = 1...n) for all j. While it may not be strictly 16519c2daa00SOllivier Robert * necessary, Make sure each root has no factors in common with 16529c2daa00SOllivier Robert * q. 16539c2daa00SOllivier Robert */ 16549c2daa00SOllivier Robert fprintf(stderr, 16559c2daa00SOllivier Robert "Generating polynomial coefficients for %d roots (%d bits)\n", 1656*f391d6bcSXin LI n, BN_num_bits(q)); 16579c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 16589c2daa00SOllivier Robert x[j] = BN_new(); 16592b15cb3dSCy Schubert 16609c2daa00SOllivier Robert while (1) { 1661*f391d6bcSXin LI BN_rand(x[j], BN_num_bits(q), 0, 0); 1662*f391d6bcSXin LI BN_mod(x[j], x[j], q, ctx); 1663*f391d6bcSXin LI BN_gcd(u, x[j], q, ctx); 16649c2daa00SOllivier Robert if (BN_is_one(u)) 16659c2daa00SOllivier Robert break; 16669c2daa00SOllivier Robert } 16679c2daa00SOllivier Robert } 16689c2daa00SOllivier Robert 16699c2daa00SOllivier Robert /* 16709c2daa00SOllivier Robert * Generate polynomial coefficients a[i] (i = 0...n) from the 16719c2daa00SOllivier Robert * expansion of root products (x - x[j]) mod q for all j. The 16729c2daa00SOllivier Robert * method is a present from Charlie Boncelet. 16739c2daa00SOllivier Robert */ 16749c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 16759c2daa00SOllivier Robert a[i] = BN_new(); 16769c2daa00SOllivier Robert BN_one(a[i]); 16779c2daa00SOllivier Robert } 16789c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 16799c2daa00SOllivier Robert BN_zero(w); 16809c2daa00SOllivier Robert for (i = 0; i < j; i++) { 1681*f391d6bcSXin LI BN_copy(u, q); 1682*f391d6bcSXin LI BN_mod_mul(v, a[i], x[j], q, ctx); 16839c2daa00SOllivier Robert BN_sub(u, u, v); 16849c2daa00SOllivier Robert BN_add(u, u, w); 16859c2daa00SOllivier Robert BN_copy(w, a[i]); 1686*f391d6bcSXin LI BN_mod(a[i], u, q, ctx); 16879c2daa00SOllivier Robert } 16889c2daa00SOllivier Robert } 16899c2daa00SOllivier Robert 16909c2daa00SOllivier Robert /* 1691*f391d6bcSXin LI * Generate gs[i] = g^a[i] mod p for all i and the generator g. 16929c2daa00SOllivier Robert */ 16939c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 1694*f391d6bcSXin LI gs[i] = BN_new(); 1695*f391d6bcSXin LI BN_mod_exp(gs[i], g, a[i], p, ctx); 16969c2daa00SOllivier Robert } 16979c2daa00SOllivier Robert 16989c2daa00SOllivier Robert /* 1699*f391d6bcSXin LI * Verify prod(gs[i]^(a[i] x[j]^i)) = 1 for all i, j. Note the 1700*f391d6bcSXin LI * a[i] x[j]^i exponent is computed mod q, but the gs[i] is 17012b15cb3dSCy Schubert * computed mod p. also note the expression given in the paper 17022b15cb3dSCy Schubert * is incorrect. 17039c2daa00SOllivier Robert */ 17049c2daa00SOllivier Robert temp = 1; 17059c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17069c2daa00SOllivier Robert BN_one(u); 17079c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 17089c2daa00SOllivier Robert BN_set_word(v, i); 1709*f391d6bcSXin LI BN_mod_exp(v, x[j], v, q, ctx); 1710*f391d6bcSXin LI BN_mod_mul(v, v, a[i], q, ctx); 1711*f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); 1712*f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 17139c2daa00SOllivier Robert } 17149c2daa00SOllivier Robert if (!BN_is_one(u)) 17159c2daa00SOllivier Robert temp = 0; 17169c2daa00SOllivier Robert } 17179c2daa00SOllivier Robert fprintf(stderr, 1718*f391d6bcSXin LI "Confirm prod(gs[i]^(x[j]^i)) = 1 for all i, j: %s\n", temp ? 17199c2daa00SOllivier Robert "yes" : "no"); 17209c2daa00SOllivier Robert if (!temp) { 17219c2daa00SOllivier Robert return (NULL); 17229c2daa00SOllivier Robert } 17239c2daa00SOllivier Robert 17249c2daa00SOllivier Robert /* 17259c2daa00SOllivier Robert * Make private encryption key A. Keep it around for awhile, 17269c2daa00SOllivier Robert * since it is expensive to compute. 17279c2daa00SOllivier Robert */ 17289c2daa00SOllivier Robert biga = BN_new(); 17292b15cb3dSCy Schubert 17309c2daa00SOllivier Robert BN_one(biga); 17319c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17329c2daa00SOllivier Robert for (i = 0; i < n; i++) { 17339c2daa00SOllivier Robert BN_set_word(v, i); 1734*f391d6bcSXin LI BN_mod_exp(v, x[j], v, q, ctx); 1735*f391d6bcSXin LI BN_mod_exp(v, gs[i], v, p, ctx); 1736*f391d6bcSXin LI BN_mod_mul(biga, biga, v, p, ctx); 17379c2daa00SOllivier Robert } 17389c2daa00SOllivier Robert } 17399c2daa00SOllivier Robert 17409c2daa00SOllivier Robert /* 17419c2daa00SOllivier Robert * Roll private random group key b mod q (0 < b < q), where 17422b15cb3dSCy Schubert * gcd(b, q) = 1 to guarantee b^-1 exists, then compute b^-1 17439c2daa00SOllivier Robert * mod q. If b is changed, the client keys must be recomputed. 17449c2daa00SOllivier Robert */ 17459c2daa00SOllivier Robert while (1) { 1746*f391d6bcSXin LI BN_rand(b, BN_num_bits(q), 0, 0); 1747*f391d6bcSXin LI BN_mod(b, b, q, ctx); 1748*f391d6bcSXin LI BN_gcd(u, b, q, ctx); 17499c2daa00SOllivier Robert if (BN_is_one(u)) 17509c2daa00SOllivier Robert break; 17519c2daa00SOllivier Robert } 1752*f391d6bcSXin LI BN_mod_inverse(b1, b, q, ctx); 17539c2daa00SOllivier Robert 17549c2daa00SOllivier Robert /* 17559c2daa00SOllivier Robert * Make private client keys (xbar[j], xhat[j]) for all j. Note 17562b15cb3dSCy Schubert * that the keys for the jth client do not s1[j] or the product 17572b15cb3dSCy Schubert * s1[j]) (j = 1...n) which is q by construction. 17582b15cb3dSCy Schubert * 17592b15cb3dSCy Schubert * Compute the factor w such that w s1[j] = s1[j] for all j. The 17602b15cb3dSCy Schubert * easy way to do this is to compute (q + s1[j]) / s1[j]. 17612b15cb3dSCy Schubert * Exercise for the student: prove the remainder is always zero. 17629c2daa00SOllivier Robert */ 17639c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17649c2daa00SOllivier Robert xbar[j] = BN_new(); xhat[j] = BN_new(); 17652b15cb3dSCy Schubert 1766*f391d6bcSXin LI BN_add(w, q, s1[j]); 17672b15cb3dSCy Schubert BN_div(w, u, w, s1[j], ctx); 17689c2daa00SOllivier Robert BN_zero(xbar[j]); 17699c2daa00SOllivier Robert BN_set_word(v, n); 17709c2daa00SOllivier Robert for (i = 1; i <= n; i++) { 17719c2daa00SOllivier Robert if (i == j) 17729c2daa00SOllivier Robert continue; 17732b15cb3dSCy Schubert 1774*f391d6bcSXin LI BN_mod_exp(u, x[i], v, q, ctx); 17759c2daa00SOllivier Robert BN_add(xbar[j], xbar[j], u); 17769c2daa00SOllivier Robert } 1777*f391d6bcSXin LI BN_mod_mul(xbar[j], xbar[j], b1, q, ctx); 1778*f391d6bcSXin LI BN_mod_exp(xhat[j], x[j], v, q, ctx); 1779*f391d6bcSXin LI BN_mod_mul(xhat[j], xhat[j], w, q, ctx); 17809c2daa00SOllivier Robert } 17819c2daa00SOllivier Robert 17829c2daa00SOllivier Robert /* 17832b15cb3dSCy Schubert * We revoke client j by dividing q by s1[j]. The quotient 17842b15cb3dSCy Schubert * becomes the enabling key s. Note we always have to revoke 17852b15cb3dSCy Schubert * one key; otherwise, the plaintext and cryptotext would be 17862b15cb3dSCy Schubert * identical. For the present there are no provisions to revoke 17872b15cb3dSCy Schubert * additional keys, so we sail on with only token revocations. 17889c2daa00SOllivier Robert */ 17892b15cb3dSCy Schubert s = BN_new(); 1790*f391d6bcSXin LI BN_copy(s, q); 17912b15cb3dSCy Schubert BN_div(s, u, s, s1[n], ctx); 17929c2daa00SOllivier Robert 17939c2daa00SOllivier Robert /* 17942b15cb3dSCy Schubert * For each combination of clients to be revoked, make private 17952b15cb3dSCy Schubert * encryption key E = A^s and partial decryption keys gbar = g^s 17962b15cb3dSCy Schubert * and ghat = g^(s b), all mod p. The servers use these keys to 17972b15cb3dSCy Schubert * compute the session encryption key and partial decryption 17982b15cb3dSCy Schubert * keys. These values must be regenerated if the enabling key is 17992b15cb3dSCy Schubert * changed. 18009c2daa00SOllivier Robert */ 18019c2daa00SOllivier Robert bige = BN_new(); gbar = BN_new(); ghat = BN_new(); 1802*f391d6bcSXin LI BN_mod_exp(bige, biga, s, p, ctx); 1803*f391d6bcSXin LI BN_mod_exp(gbar, g, s, p, ctx); 1804*f391d6bcSXin LI BN_mod_mul(v, s, b, q, ctx); 1805*f391d6bcSXin LI BN_mod_exp(ghat, g, v, p, ctx); 18069c2daa00SOllivier Robert 18079c2daa00SOllivier Robert /* 18082b15cb3dSCy Schubert * Notes: We produce the key media in three steps. The first 18092b15cb3dSCy Schubert * step is to generate the system parameters p, q, g, b, A and 18102b15cb3dSCy Schubert * the enabling keys s1[j]. Associated with each s1[j] are 18112b15cb3dSCy Schubert * parameters xbar[j] and xhat[j]. All of these parameters are 18122b15cb3dSCy Schubert * retained in a data structure protecteted by the trusted-agent 18132b15cb3dSCy Schubert * password. The p, xbar[j] and xhat[j] paremeters are 18142b15cb3dSCy Schubert * distributed to the j clients. When the client keys are to be 18152b15cb3dSCy Schubert * activated, the enabled keys are multipied together to form 18162b15cb3dSCy Schubert * the master enabling key s. This and the other parameters are 18172b15cb3dSCy Schubert * used to compute the server encryption key E and the partial 18182b15cb3dSCy Schubert * decryption keys gbar and ghat. 18199c2daa00SOllivier Robert * 18202b15cb3dSCy Schubert * In the identity exchange the client rolls random r and sends 18212b15cb3dSCy Schubert * it to the server. The server rolls random k, which is used 18222b15cb3dSCy Schubert * only once, then computes the session key E^k and partial 18232b15cb3dSCy Schubert * decryption keys gbar^k and ghat^k. The server sends the 18242b15cb3dSCy Schubert * encrypted r along with gbar^k and ghat^k to the client. The 18252b15cb3dSCy Schubert * client completes the decryption and verifies it matches r. 18269c2daa00SOllivier Robert */ 18279c2daa00SOllivier Robert /* 18282b15cb3dSCy Schubert * Write the MV trusted-agent parameters and keys as a DSA 18292b15cb3dSCy Schubert * private key encoded in PEM. 18309c2daa00SOllivier Robert * 18319c2daa00SOllivier Robert * p modulus p 18322b15cb3dSCy Schubert * q modulus q 18332b15cb3dSCy Schubert * g generator g 18342b15cb3dSCy Schubert * priv_key A mod p 18352b15cb3dSCy Schubert * pub_key b mod q 18362b15cb3dSCy Schubert * (remaining values are not used) 18379c2daa00SOllivier Robert */ 18382b15cb3dSCy Schubert i = 0; 18392b15cb3dSCy Schubert str = fheader("MVta", "mvta", groupname); 18402b15cb3dSCy Schubert fprintf(stderr, "Generating MV trusted-authority keys\n"); 1841*f391d6bcSXin LI BN_copy(priv_key, biga); 1842*f391d6bcSXin LI BN_copy(pub_key, b); 1843*f391d6bcSXin LI DSA_set0_key(dsa, pub_key, priv_key); 18449c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 18459c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 18462b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 18472b15cb3dSCy Schubert passwd1); 18482b15cb3dSCy Schubert evpars[i++] = pkey; 18499c2daa00SOllivier Robert if (debug) 18502b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 18519c2daa00SOllivier Robert 18529c2daa00SOllivier Robert /* 18532b15cb3dSCy Schubert * Append the MV server parameters and keys as a DSA key encoded 18542b15cb3dSCy Schubert * in PEM. 18552b15cb3dSCy Schubert * 18562b15cb3dSCy Schubert * p modulus p 18572b15cb3dSCy Schubert * q modulus q (used only when generating k) 18582b15cb3dSCy Schubert * g bige 18592b15cb3dSCy Schubert * priv_key gbar 18602b15cb3dSCy Schubert * pub_key ghat 18612b15cb3dSCy Schubert * (remaining values are not used) 18629c2daa00SOllivier Robert */ 18632b15cb3dSCy Schubert fprintf(stderr, "Generating MV server keys\n"); 18642b15cb3dSCy Schubert dsa2 = DSA_new(); 1865*f391d6bcSXin LI DSA_set0_pqg(dsa2, BN_dup(p), BN_dup(q), BN_dup(bige)); 1866*f391d6bcSXin LI DSA_set0_key(dsa2, BN_dup(ghat), BN_dup(gbar)); 18672b15cb3dSCy Schubert pkey1 = EVP_PKEY_new(); 18682b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey1, dsa2); 18692b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey1, cipher, NULL, 0, NULL, 18702b15cb3dSCy Schubert passwd1); 18712b15cb3dSCy Schubert evpars[i++] = pkey1; 18722b15cb3dSCy Schubert if (debug) 18732b15cb3dSCy Schubert DSA_print_fp(stderr, dsa2, 0); 18749c2daa00SOllivier Robert 18759c2daa00SOllivier Robert /* 18762b15cb3dSCy Schubert * Append the MV client parameters for each client j as DSA keys 18772b15cb3dSCy Schubert * encoded in PEM. 18789c2daa00SOllivier Robert * 18799c2daa00SOllivier Robert * p modulus p 18809c2daa00SOllivier Robert * priv_key xbar[j] mod q 18819c2daa00SOllivier Robert * pub_key xhat[j] mod q 18829c2daa00SOllivier Robert * (remaining values are not used) 18839c2daa00SOllivier Robert */ 18842b15cb3dSCy Schubert fprintf(stderr, "Generating %d MV client keys\n", n); 18852b15cb3dSCy Schubert for (j = 1; j <= n; j++) { 18862b15cb3dSCy Schubert sdsa = DSA_new(); 1887*f391d6bcSXin LI DSA_set0_pqg(sdsa, BN_dup(p), BN_dup(BN_value_one()), 1888*f391d6bcSXin LI BN_dup(BN_value_one())); 1889*f391d6bcSXin LI DSA_set0_key(sdsa, BN_dup(xhat[j]), BN_dup(xbar[j])); 18905e91a9b7SOllivier Robert pkey1 = EVP_PKEY_new(); 18915e91a9b7SOllivier Robert EVP_PKEY_set1_DSA(pkey1, sdsa); 18922b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey1, cipher, NULL, 0, 18932b15cb3dSCy Schubert NULL, passwd1); 18942b15cb3dSCy Schubert evpars[i++] = pkey1; 18959c2daa00SOllivier Robert if (debug) 18962b15cb3dSCy Schubert DSA_print_fp(stderr, sdsa, 0); 18972b15cb3dSCy Schubert 18982b15cb3dSCy Schubert /* 1899*f391d6bcSXin LI * The product (gbar^k)^xbar[j] (ghat^k)^xhat[j] and E 19002b15cb3dSCy Schubert * are inverses of each other. We check that the product 19012b15cb3dSCy Schubert * is one for each client except the ones that have been 19022b15cb3dSCy Schubert * revoked. 19032b15cb3dSCy Schubert */ 1904*f391d6bcSXin LI BN_mod_exp(v, gbar, xhat[j], p, ctx); 1905*f391d6bcSXin LI BN_mod_exp(u, ghat, xbar[j], p, ctx); 1906*f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 1907*f391d6bcSXin LI BN_mod_mul(u, u, bige, p, ctx); 19082b15cb3dSCy Schubert if (!BN_is_one(u)) { 19092b15cb3dSCy Schubert fprintf(stderr, "Revoke key %d\n", j); 19102b15cb3dSCy Schubert continue; 19119c2daa00SOllivier Robert } 19122b15cb3dSCy Schubert } 19132b15cb3dSCy Schubert evpars[i++] = NULL; 19142b15cb3dSCy Schubert fclose(str); 19159c2daa00SOllivier Robert 19169c2daa00SOllivier Robert /* 19179c2daa00SOllivier Robert * Free the countries. 19189c2daa00SOllivier Robert */ 19199c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 1920*f391d6bcSXin LI BN_free(a[i]); BN_free(gs[i]); 19219c2daa00SOllivier Robert } 19222b15cb3dSCy Schubert for (j = 1; j <= n; j++) { 19232b15cb3dSCy Schubert BN_free(x[j]); BN_free(xbar[j]); BN_free(xhat[j]); 19242b15cb3dSCy Schubert BN_free(s1[j]); 19252b15cb3dSCy Schubert } 19269c2daa00SOllivier Robert return (pkey); 19279c2daa00SOllivier Robert } 19289c2daa00SOllivier Robert 19299c2daa00SOllivier Robert 19309c2daa00SOllivier Robert /* 19312b15cb3dSCy Schubert * Generate X509v3 certificate. 19329c2daa00SOllivier Robert * 19339c2daa00SOllivier Robert * The certificate consists of the version number, serial number, 19349c2daa00SOllivier Robert * validity interval, issuer name, subject name and public key. For a 19359c2daa00SOllivier Robert * self-signed certificate, the issuer name is the same as the subject 19369c2daa00SOllivier Robert * name and these items are signed using the subject private key. The 19379c2daa00SOllivier Robert * validity interval extends from the current time to the same time one 19389c2daa00SOllivier Robert * year hence. For NTP purposes, it is convenient to use the NTP seconds 19399c2daa00SOllivier Robert * of the current time as the serial number. 19409c2daa00SOllivier Robert */ 19419c2daa00SOllivier Robert int 19429c2daa00SOllivier Robert x509 ( 19432b15cb3dSCy Schubert EVP_PKEY *pkey, /* signing key */ 19442b15cb3dSCy Schubert const EVP_MD *md, /* signature/digest scheme */ 19459c2daa00SOllivier Robert char *gqpub, /* identity extension (hex string) */ 19462b15cb3dSCy Schubert const char *exten, /* private cert extension */ 19472b15cb3dSCy Schubert char *name /* subject/issuer name */ 19489c2daa00SOllivier Robert ) 19499c2daa00SOllivier Robert { 19509c2daa00SOllivier Robert X509 *cert; /* X509 certificate */ 19519c2daa00SOllivier Robert X509_NAME *subj; /* distinguished (common) name */ 19529c2daa00SOllivier Robert X509_EXTENSION *ex; /* X509v3 extension */ 19539c2daa00SOllivier Robert FILE *str; /* file handle */ 19549c2daa00SOllivier Robert ASN1_INTEGER *serial; /* serial number */ 19559c2daa00SOllivier Robert const char *id; /* digest/signature scheme name */ 19569c2daa00SOllivier Robert char pathbuf[MAXFILENAME + 1]; 19579c2daa00SOllivier Robert 19589c2daa00SOllivier Robert /* 19599c2daa00SOllivier Robert * Generate X509 self-signed certificate. 19609c2daa00SOllivier Robert * 19619c2daa00SOllivier Robert * Set the certificate serial to the NTP seconds for grins. Set 19622b15cb3dSCy Schubert * the version to 3. Set the initial validity to the current 19632b15cb3dSCy Schubert * time and the finalvalidity one year hence. 19649c2daa00SOllivier Robert */ 1965*f391d6bcSXin LI id = OBJ_nid2sn(EVP_MD_pkey_type(md)); 19662b15cb3dSCy Schubert fprintf(stderr, "Generating new certificate %s %s\n", name, id); 19679c2daa00SOllivier Robert cert = X509_new(); 19689c2daa00SOllivier Robert X509_set_version(cert, 2L); 19699c2daa00SOllivier Robert serial = ASN1_INTEGER_new(); 19702b15cb3dSCy Schubert ASN1_INTEGER_set(serial, (long)epoch + JAN_1970); 19719c2daa00SOllivier Robert X509_set_serialNumber(cert, serial); 19729c2daa00SOllivier Robert ASN1_INTEGER_free(serial); 1973ea906c41SOllivier Robert X509_time_adj(X509_get_notBefore(cert), 0L, &epoch); 19742b15cb3dSCy Schubert X509_time_adj(X509_get_notAfter(cert), lifetime * SECSPERDAY, &epoch); 19759c2daa00SOllivier Robert subj = X509_get_subject_name(cert); 19769c2daa00SOllivier Robert X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, 19773311ff84SXin LI (u_char *)name, -1, -1, 0); 19789c2daa00SOllivier Robert subj = X509_get_issuer_name(cert); 19799c2daa00SOllivier Robert X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, 19803311ff84SXin LI (u_char *)name, -1, -1, 0); 19819c2daa00SOllivier Robert if (!X509_set_pubkey(cert, pkey)) { 19822b15cb3dSCy Schubert fprintf(stderr, "Assign certificate signing key fails\n%s\n", 19839c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 19849c2daa00SOllivier Robert X509_free(cert); 19859c2daa00SOllivier Robert return (0); 19869c2daa00SOllivier Robert } 19879c2daa00SOllivier Robert 19889c2daa00SOllivier Robert /* 19899c2daa00SOllivier Robert * Add X509v3 extensions if present. These represent the minimum 19909c2daa00SOllivier Robert * set defined in RFC3280 less the certificate_policy extension, 19919c2daa00SOllivier Robert * which is seriously obfuscated in OpenSSL. 19929c2daa00SOllivier Robert */ 19939c2daa00SOllivier Robert /* 19949c2daa00SOllivier Robert * The basic_constraints extension CA:TRUE allows servers to 19959c2daa00SOllivier Robert * sign client certficitates. 19969c2daa00SOllivier Robert */ 19979c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_basic_constraints, 19989c2daa00SOllivier Robert BASIC_CONSTRAINTS); 19999c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, 20002b15cb3dSCy Schubert _UC(BASIC_CONSTRAINTS)); 20019c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20029c2daa00SOllivier Robert fprintf(stderr, "Add extension field fails\n%s\n", 20039c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20049c2daa00SOllivier Robert return (0); 20059c2daa00SOllivier Robert } 20069c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20079c2daa00SOllivier Robert 20089c2daa00SOllivier Robert /* 20099c2daa00SOllivier Robert * The key_usage extension designates the purposes the key can 20109c2daa00SOllivier Robert * be used for. 20119c2daa00SOllivier Robert */ 20129c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_key_usage, KEY_USAGE); 20132b15cb3dSCy Schubert ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, _UC(KEY_USAGE)); 20149c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20159c2daa00SOllivier Robert fprintf(stderr, "Add extension field fails\n%s\n", 20169c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20179c2daa00SOllivier Robert return (0); 20189c2daa00SOllivier Robert } 20199c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20209c2daa00SOllivier Robert /* 20219c2daa00SOllivier Robert * The subject_key_identifier is used for the GQ public key. 20229c2daa00SOllivier Robert * This should not be controversial. 20239c2daa00SOllivier Robert */ 20249c2daa00SOllivier Robert if (gqpub != NULL) { 20259c2daa00SOllivier Robert fprintf(stderr, "%s\n", LN_subject_key_identifier); 20269c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, 20279c2daa00SOllivier Robert NID_subject_key_identifier, gqpub); 20289c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20299c2daa00SOllivier Robert fprintf(stderr, 20309c2daa00SOllivier Robert "Add extension field fails\n%s\n", 20319c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20329c2daa00SOllivier Robert return (0); 20339c2daa00SOllivier Robert } 20349c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20359c2daa00SOllivier Robert } 20369c2daa00SOllivier Robert 20379c2daa00SOllivier Robert /* 20389c2daa00SOllivier Robert * The extended key usage extension is used for special purpose 20399c2daa00SOllivier Robert * here. The semantics probably do not conform to the designer's 20409c2daa00SOllivier Robert * intent and will likely change in future. 20419c2daa00SOllivier Robert * 20429c2daa00SOllivier Robert * "trustRoot" designates a root authority 20439c2daa00SOllivier Robert * "private" designates a private certificate 20449c2daa00SOllivier Robert */ 20459c2daa00SOllivier Robert if (exten != NULL) { 20469c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_ext_key_usage, exten); 20479c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, 20482b15cb3dSCy Schubert NID_ext_key_usage, _UC(exten)); 20499c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20509c2daa00SOllivier Robert fprintf(stderr, 20519c2daa00SOllivier Robert "Add extension field fails\n%s\n", 20529c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20539c2daa00SOllivier Robert return (0); 20549c2daa00SOllivier Robert } 20559c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20569c2daa00SOllivier Robert } 20579c2daa00SOllivier Robert 20589c2daa00SOllivier Robert /* 20599c2daa00SOllivier Robert * Sign and verify. 20609c2daa00SOllivier Robert */ 20619c2daa00SOllivier Robert X509_sign(cert, pkey, md); 20622b15cb3dSCy Schubert if (X509_verify(cert, pkey) <= 0) { 20639c2daa00SOllivier Robert fprintf(stderr, "Verify %s certificate fails\n%s\n", id, 20649c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20659c2daa00SOllivier Robert X509_free(cert); 20669c2daa00SOllivier Robert return (0); 20679c2daa00SOllivier Robert } 20689c2daa00SOllivier Robert 20699c2daa00SOllivier Robert /* 20709c2daa00SOllivier Robert * Write the certificate encoded in PEM. 20719c2daa00SOllivier Robert */ 20722b15cb3dSCy Schubert snprintf(pathbuf, sizeof(pathbuf), "%scert", id); 20732b15cb3dSCy Schubert str = fheader(pathbuf, "cert", hostname); 20749c2daa00SOllivier Robert PEM_write_X509(str, cert); 20759c2daa00SOllivier Robert fclose(str); 20769c2daa00SOllivier Robert if (debug) 20772b15cb3dSCy Schubert X509_print_fp(stderr, cert); 20789c2daa00SOllivier Robert X509_free(cert); 20799c2daa00SOllivier Robert return (1); 20809c2daa00SOllivier Robert } 20819c2daa00SOllivier Robert 20822b15cb3dSCy Schubert #if 0 /* asn2ntp is used only with commercial certificates */ 20839c2daa00SOllivier Robert /* 20849c2daa00SOllivier Robert * asn2ntp - convert ASN1_TIME time structure to NTP time 20859c2daa00SOllivier Robert */ 20869c2daa00SOllivier Robert u_long 20879c2daa00SOllivier Robert asn2ntp ( 20889c2daa00SOllivier Robert ASN1_TIME *asn1time /* pointer to ASN1_TIME structure */ 20899c2daa00SOllivier Robert ) 20909c2daa00SOllivier Robert { 20919c2daa00SOllivier Robert char *v; /* pointer to ASN1_TIME string */ 20929c2daa00SOllivier Robert struct tm tm; /* time decode structure time */ 20939c2daa00SOllivier Robert 20949c2daa00SOllivier Robert /* 20959c2daa00SOllivier Robert * Extract time string YYMMDDHHMMSSZ from ASN.1 time structure. 20969c2daa00SOllivier Robert * Note that the YY, MM, DD fields start with one, the HH, MM, 20979c2daa00SOllivier Robert * SS fiels start with zero and the Z character should be 'Z' 20989c2daa00SOllivier Robert * for UTC. Also note that years less than 50 map to years 20999c2daa00SOllivier Robert * greater than 100. Dontcha love ASN.1? 21009c2daa00SOllivier Robert */ 21019c2daa00SOllivier Robert if (asn1time->length > 13) 21029c2daa00SOllivier Robert return (-1); 21039c2daa00SOllivier Robert v = (char *)asn1time->data; 21049c2daa00SOllivier Robert tm.tm_year = (v[0] - '0') * 10 + v[1] - '0'; 21059c2daa00SOllivier Robert if (tm.tm_year < 50) 21069c2daa00SOllivier Robert tm.tm_year += 100; 21079c2daa00SOllivier Robert tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1; 21089c2daa00SOllivier Robert tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0'; 21099c2daa00SOllivier Robert tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0'; 21109c2daa00SOllivier Robert tm.tm_min = (v[8] - '0') * 10 + v[9] - '0'; 21119c2daa00SOllivier Robert tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0'; 21129c2daa00SOllivier Robert tm.tm_wday = 0; 21139c2daa00SOllivier Robert tm.tm_yday = 0; 21149c2daa00SOllivier Robert tm.tm_isdst = 0; 21159c2daa00SOllivier Robert return (mktime(&tm) + JAN_1970); 21169c2daa00SOllivier Robert } 21179c2daa00SOllivier Robert #endif 21189c2daa00SOllivier Robert 21199c2daa00SOllivier Robert /* 21209c2daa00SOllivier Robert * Callback routine 21219c2daa00SOllivier Robert */ 21229c2daa00SOllivier Robert void 21239c2daa00SOllivier Robert cb ( 21249c2daa00SOllivier Robert int n1, /* arg 1 */ 21259c2daa00SOllivier Robert int n2, /* arg 2 */ 21269c2daa00SOllivier Robert void *chr /* arg 3 */ 21279c2daa00SOllivier Robert ) 21289c2daa00SOllivier Robert { 21299c2daa00SOllivier Robert switch (n1) { 21309c2daa00SOllivier Robert case 0: 21319c2daa00SOllivier Robert d0++; 21329c2daa00SOllivier Robert fprintf(stderr, "%s %d %d %lu\r", (char *)chr, n1, n2, 21339c2daa00SOllivier Robert d0); 21349c2daa00SOllivier Robert break; 21359c2daa00SOllivier Robert case 1: 21369c2daa00SOllivier Robert d1++; 21379c2daa00SOllivier Robert fprintf(stderr, "%s\t\t%d %d %lu\r", (char *)chr, n1, 21389c2daa00SOllivier Robert n2, d1); 21399c2daa00SOllivier Robert break; 21409c2daa00SOllivier Robert case 2: 21419c2daa00SOllivier Robert d2++; 21429c2daa00SOllivier Robert fprintf(stderr, "%s\t\t\t\t%d %d %lu\r", (char *)chr, 21439c2daa00SOllivier Robert n1, n2, d2); 21449c2daa00SOllivier Robert break; 21459c2daa00SOllivier Robert case 3: 21469c2daa00SOllivier Robert d3++; 21479c2daa00SOllivier Robert fprintf(stderr, "%s\t\t\t\t\t\t%d %d %lu\r", 21489c2daa00SOllivier Robert (char *)chr, n1, n2, d3); 21499c2daa00SOllivier Robert break; 21509c2daa00SOllivier Robert } 21519c2daa00SOllivier Robert } 21529c2daa00SOllivier Robert 21539c2daa00SOllivier Robert 21549c2daa00SOllivier Robert /* 21559c2daa00SOllivier Robert * Generate key 21569c2daa00SOllivier Robert */ 21579c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 21589c2daa00SOllivier Robert genkey( 21592b15cb3dSCy Schubert const char *type, /* key type (RSA or DSA) */ 21602b15cb3dSCy Schubert const char *id /* file name id */ 21619c2daa00SOllivier Robert ) 21629c2daa00SOllivier Robert { 21639c2daa00SOllivier Robert if (type == NULL) 21649c2daa00SOllivier Robert return (NULL); 21659c2daa00SOllivier Robert if (strcmp(type, "RSA") == 0) 21669c2daa00SOllivier Robert return (gen_rsa(id)); 21679c2daa00SOllivier Robert 21689c2daa00SOllivier Robert else if (strcmp(type, "DSA") == 0) 21699c2daa00SOllivier Robert return (gen_dsa(id)); 21709c2daa00SOllivier Robert 21719c2daa00SOllivier Robert fprintf(stderr, "Invalid %s key type %s\n", id, type); 21729c2daa00SOllivier Robert return (NULL); 21739c2daa00SOllivier Robert } 2174*f391d6bcSXin LI 2175*f391d6bcSXin LI static RSA* 2176*f391d6bcSXin LI genRsaKeyPair( 2177*f391d6bcSXin LI int bits, 2178*f391d6bcSXin LI char * what 2179*f391d6bcSXin LI ) 2180*f391d6bcSXin LI { 2181*f391d6bcSXin LI RSA * rsa = RSA_new(); 2182*f391d6bcSXin LI BN_GENCB * gcb = BN_GENCB_new(); 2183*f391d6bcSXin LI BIGNUM * bne = BN_new(); 2184*f391d6bcSXin LI 2185*f391d6bcSXin LI if (gcb) 2186*f391d6bcSXin LI BN_GENCB_set_old(gcb, cb, what); 2187*f391d6bcSXin LI if (bne) 2188*f391d6bcSXin LI BN_set_word(bne, 65537); 2189*f391d6bcSXin LI if (!(rsa && gcb && bne && RSA_generate_key_ex( 2190*f391d6bcSXin LI rsa, bits, bne, gcb))) 2191*f391d6bcSXin LI { 2192*f391d6bcSXin LI RSA_free(rsa); 2193*f391d6bcSXin LI rsa = NULL; 2194*f391d6bcSXin LI } 2195*f391d6bcSXin LI BN_GENCB_free(gcb); 2196*f391d6bcSXin LI BN_free(bne); 2197*f391d6bcSXin LI return rsa; 2198*f391d6bcSXin LI } 2199*f391d6bcSXin LI 2200*f391d6bcSXin LI static DSA* 2201*f391d6bcSXin LI genDsaParams( 2202*f391d6bcSXin LI int bits, 2203*f391d6bcSXin LI char * what 2204*f391d6bcSXin LI ) 2205*f391d6bcSXin LI { 2206*f391d6bcSXin LI 2207*f391d6bcSXin LI DSA * dsa = DSA_new(); 2208*f391d6bcSXin LI BN_GENCB * gcb = BN_GENCB_new(); 2209*f391d6bcSXin LI u_char seed[20]; 2210*f391d6bcSXin LI 2211*f391d6bcSXin LI if (gcb) 2212*f391d6bcSXin LI BN_GENCB_set_old(gcb, cb, what); 2213*f391d6bcSXin LI RAND_bytes(seed, sizeof(seed)); 2214*f391d6bcSXin LI if (!(dsa && gcb && DSA_generate_parameters_ex( 2215*f391d6bcSXin LI dsa, bits, seed, sizeof(seed), NULL, NULL, gcb))) 2216*f391d6bcSXin LI { 2217*f391d6bcSXin LI DSA_free(dsa); 2218*f391d6bcSXin LI dsa = NULL; 2219*f391d6bcSXin LI } 2220*f391d6bcSXin LI BN_GENCB_free(gcb); 2221*f391d6bcSXin LI return dsa; 2222*f391d6bcSXin LI } 2223*f391d6bcSXin LI 22242b15cb3dSCy Schubert #endif /* AUTOKEY */ 22259c2daa00SOllivier Robert 22269c2daa00SOllivier Robert 22279c2daa00SOllivier Robert /* 22282b15cb3dSCy Schubert * Generate file header and link 22299c2daa00SOllivier Robert */ 22309c2daa00SOllivier Robert FILE * 22319c2daa00SOllivier Robert fheader ( 22322b15cb3dSCy Schubert const char *file, /* file name id */ 22332b15cb3dSCy Schubert const char *ulink, /* linkname */ 22342b15cb3dSCy Schubert const char *owner /* owner name */ 22359c2daa00SOllivier Robert ) 22369c2daa00SOllivier Robert { 22379c2daa00SOllivier Robert FILE *str; /* file handle */ 22382b15cb3dSCy Schubert char linkname[MAXFILENAME]; /* link name */ 22392b15cb3dSCy Schubert int temp; 2240a25439b6SCy Schubert #ifdef HAVE_UMASK 2241a25439b6SCy Schubert mode_t orig_umask; 2242a25439b6SCy Schubert #endif 22439c2daa00SOllivier Robert 22442b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_%s_%s.%u", file, 22452b15cb3dSCy Schubert owner, fstamp); 2246a25439b6SCy Schubert #ifdef HAVE_UMASK 2247a25439b6SCy Schubert orig_umask = umask( S_IWGRP | S_IRWXO ); 2248a25439b6SCy Schubert str = fopen(filename, "w"); 2249a25439b6SCy Schubert (void) umask(orig_umask); 2250a25439b6SCy Schubert #else 2251a25439b6SCy Schubert str = fopen(filename, "w"); 2252a25439b6SCy Schubert #endif 2253a25439b6SCy Schubert if (str == NULL) { 22549c2daa00SOllivier Robert perror("Write"); 22559c2daa00SOllivier Robert exit (-1); 22569c2daa00SOllivier Robert } 2257a25439b6SCy Schubert if (strcmp(ulink, "md5") == 0) { 2258a25439b6SCy Schubert strcpy(linkname,"ntp.keys"); 2259a25439b6SCy Schubert } else { 22602b15cb3dSCy Schubert snprintf(linkname, sizeof(linkname), "ntpkey_%s_%s", ulink, 22612b15cb3dSCy Schubert hostname); 2262a25439b6SCy Schubert } 22632b15cb3dSCy Schubert (void)remove(linkname); /* The symlink() line below matters */ 22649c2daa00SOllivier Robert temp = symlink(filename, linkname); 22659c2daa00SOllivier Robert if (temp < 0) 22662b15cb3dSCy Schubert perror(file); 22672b15cb3dSCy Schubert fprintf(stderr, "Generating new %s file and link\n", ulink); 22689c2daa00SOllivier Robert fprintf(stderr, "%s->%s\n", linkname, filename); 22692b15cb3dSCy Schubert fprintf(str, "# %s\n# %s\n", filename, ctime(&epoch)); 22702b15cb3dSCy Schubert return (str); 22719c2daa00SOllivier Robert } 2272