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 101f0574f5cSXin LI #include "openssl/asn1.h" 1029c2daa00SOllivier Robert #include "openssl/bn.h" 103f0574f5cSXin LI #include "openssl/crypto.h" 1049c2daa00SOllivier Robert #include "openssl/evp.h" 1059c2daa00SOllivier Robert #include "openssl/err.h" 1069c2daa00SOllivier Robert #include "openssl/rand.h" 107f0574f5cSXin LI #include "openssl/opensslv.h" 1089c2daa00SOllivier Robert #include "openssl/pem.h" 109f0574f5cSXin LI #include "openssl/x509.h" 1109c2daa00SOllivier Robert #include "openssl/x509v3.h" 1119c2daa00SOllivier Robert #include <openssl/objects.h> 112f391d6bcSXin LI #include "libssl_compat.h" 1139c2daa00SOllivier Robert #endif /* OPENSSL */ 1142b15cb3dSCy Schubert #include <ssl_applink.c> 1159c2daa00SOllivier Robert 1162b15cb3dSCy Schubert #define _UC(str) ((char *)(intptr_t)(str)) 1179c2daa00SOllivier Robert /* 1189c2daa00SOllivier Robert * Cryptodefines 1199c2daa00SOllivier Robert */ 1202b15cb3dSCy Schubert #define MD5KEYS 10 /* number of keys generated of each type */ 1212b15cb3dSCy Schubert #define MD5SIZE 20 /* maximum key size */ 1222b15cb3dSCy Schubert #ifdef AUTOKEY 1239c2daa00SOllivier Robert #define PLEN 512 /* default prime modulus size (bits) */ 124*a466cc55SCy Schubert #define ILEN 512 /* default identity modulus size (bits) */ 1252b15cb3dSCy Schubert #define MVMAX 100 /* max MV parameters */ 1269c2daa00SOllivier Robert 1279c2daa00SOllivier Robert /* 1289c2daa00SOllivier Robert * Strings used in X509v3 extension fields 1299c2daa00SOllivier Robert */ 1309c2daa00SOllivier Robert #define KEY_USAGE "digitalSignature,keyCertSign" 1319c2daa00SOllivier Robert #define BASIC_CONSTRAINTS "critical,CA:TRUE" 1329c2daa00SOllivier Robert #define EXT_KEY_PRIVATE "private" 1339c2daa00SOllivier Robert #define EXT_KEY_TRUST "trustRoot" 1342b15cb3dSCy Schubert #endif /* AUTOKEY */ 1359c2daa00SOllivier Robert 1369c2daa00SOllivier Robert /* 1379c2daa00SOllivier Robert * Prototypes 1389c2daa00SOllivier Robert */ 1392b15cb3dSCy Schubert FILE *fheader (const char *, const char *, const char *); 1402b15cb3dSCy Schubert int gen_md5 (const char *); 1412b15cb3dSCy Schubert void followlink (char *, size_t); 1422b15cb3dSCy Schubert #ifdef AUTOKEY 1432b15cb3dSCy Schubert EVP_PKEY *gen_rsa (const char *); 1442b15cb3dSCy Schubert EVP_PKEY *gen_dsa (const char *); 1452b15cb3dSCy Schubert EVP_PKEY *gen_iffkey (const char *); 1462b15cb3dSCy Schubert EVP_PKEY *gen_gqkey (const char *); 1472b15cb3dSCy Schubert EVP_PKEY *gen_mvkey (const char *, EVP_PKEY **); 1482b15cb3dSCy Schubert void gen_mvserv (char *, EVP_PKEY **); 1492b15cb3dSCy Schubert int x509 (EVP_PKEY *, const EVP_MD *, char *, const char *, 1502b15cb3dSCy Schubert char *); 1512b15cb3dSCy Schubert void cb (int, int, void *); 1522b15cb3dSCy Schubert EVP_PKEY *genkey (const char *, const char *); 1532b15cb3dSCy Schubert EVP_PKEY *readkey (char *, char *, u_int *, EVP_PKEY **); 1542b15cb3dSCy Schubert void writekey (char *, char *, u_int *, EVP_PKEY **); 1552b15cb3dSCy Schubert u_long asn2ntp (ASN1_TIME *); 156f391d6bcSXin LI 157f391d6bcSXin LI static DSA* genDsaParams(int, char*); 158f391d6bcSXin LI static RSA* genRsaKeyPair(int, char*); 159f391d6bcSXin LI 1602b15cb3dSCy Schubert #endif /* AUTOKEY */ 1619c2daa00SOllivier Robert 1629c2daa00SOllivier Robert /* 1639c2daa00SOllivier Robert * Program variables 1649c2daa00SOllivier Robert */ 1659c2daa00SOllivier Robert extern char *optarg; /* command line argument */ 1669034852cSGleb Smirnoff char const *progname; 1672b15cb3dSCy Schubert u_int lifetime = DAYSPERYEAR; /* certificate lifetime (days) */ 1682b15cb3dSCy Schubert int nkeys; /* MV keys */ 1699c2daa00SOllivier Robert time_t epoch; /* Unix epoch (seconds) since 1970 */ 1702b15cb3dSCy Schubert u_int fstamp; /* NTP filestamp */ 1712b15cb3dSCy Schubert char hostbuf[MAXHOSTNAME + 1]; 1722b15cb3dSCy Schubert char *hostname = NULL; /* host, used in cert filenames */ 1732b15cb3dSCy Schubert char *groupname = NULL; /* group name */ 1742b15cb3dSCy Schubert char certnamebuf[2 * sizeof(hostbuf)]; 1752b15cb3dSCy Schubert char *certname = NULL; /* certificate subject/issuer name */ 1769c2daa00SOllivier Robert char *passwd1 = NULL; /* input private key password */ 1779c2daa00SOllivier Robert char *passwd2 = NULL; /* output private key password */ 1782b15cb3dSCy Schubert char filename[MAXFILENAME + 1]; /* file name */ 1792b15cb3dSCy Schubert #ifdef AUTOKEY 1802b15cb3dSCy Schubert u_int modulus = PLEN; /* prime modulus size (bits) */ 1812b15cb3dSCy Schubert u_int modulus2 = ILEN; /* identity modulus size (bits) */ 1829c2daa00SOllivier Robert long d0, d1, d2, d3; /* callback counters */ 1832b15cb3dSCy Schubert const EVP_CIPHER * cipher = NULL; 1842b15cb3dSCy Schubert #endif /* AUTOKEY */ 1859c2daa00SOllivier Robert 1869c2daa00SOllivier Robert #ifdef SYS_WINNT 1879c2daa00SOllivier Robert BOOL init_randfile(); 1889c2daa00SOllivier Robert 1899c2daa00SOllivier Robert /* 1902b15cb3dSCy Schubert * Don't try to follow symbolic links on Windows. Assume link == file. 1919c2daa00SOllivier Robert */ 1929c2daa00SOllivier Robert int 1932b15cb3dSCy Schubert readlink( 1942b15cb3dSCy Schubert char * link, 1952b15cb3dSCy Schubert char * file, 1962b15cb3dSCy Schubert int len 1972b15cb3dSCy Schubert ) 1982b15cb3dSCy Schubert { 1993311ff84SXin LI return (int)strlen(file); /* assume no overflow possible */ 2009c2daa00SOllivier Robert } 2012b15cb3dSCy Schubert 2029c2daa00SOllivier Robert /* 2032b15cb3dSCy Schubert * Don't try to create symbolic links on Windows, that is supported on 2042b15cb3dSCy Schubert * Vista and later only. Instead, if CreateHardLink is available (XP 2052b15cb3dSCy Schubert * and later), hardlink the linkname to the original filename. On 2062b15cb3dSCy Schubert * earlier systems, user must rename file to match expected link for 2072b15cb3dSCy Schubert * ntpd to find it. To allow building a ntp-keygen.exe which loads on 2082b15cb3dSCy Schubert * Windows pre-XP, runtime link to CreateHardLinkA(). 2099c2daa00SOllivier Robert */ 2109c2daa00SOllivier Robert int 2112b15cb3dSCy Schubert symlink( 2122b15cb3dSCy Schubert char * filename, 2132b15cb3dSCy Schubert char* linkname 2142b15cb3dSCy Schubert ) 2152b15cb3dSCy Schubert { 2162b15cb3dSCy Schubert typedef BOOL (WINAPI *PCREATEHARDLINKA)( 2172b15cb3dSCy Schubert __in LPCSTR lpFileName, 2182b15cb3dSCy Schubert __in LPCSTR lpExistingFileName, 2192b15cb3dSCy Schubert __reserved LPSECURITY_ATTRIBUTES lpSA 2202b15cb3dSCy Schubert ); 2212b15cb3dSCy Schubert static PCREATEHARDLINKA pCreateHardLinkA; 2222b15cb3dSCy Schubert static int tried; 2232b15cb3dSCy Schubert HMODULE hDll; 2242b15cb3dSCy Schubert FARPROC pfn; 2252b15cb3dSCy Schubert int link_created; 2262b15cb3dSCy Schubert int saved_errno; 2272b15cb3dSCy Schubert 2282b15cb3dSCy Schubert if (!tried) { 2292b15cb3dSCy Schubert tried = TRUE; 2302b15cb3dSCy Schubert hDll = LoadLibrary("kernel32"); 2312b15cb3dSCy Schubert pfn = GetProcAddress(hDll, "CreateHardLinkA"); 2322b15cb3dSCy Schubert pCreateHardLinkA = (PCREATEHARDLINKA)pfn; 2339c2daa00SOllivier Robert } 2342b15cb3dSCy Schubert 2352b15cb3dSCy Schubert if (NULL == pCreateHardLinkA) { 2362b15cb3dSCy Schubert errno = ENOSYS; 2372b15cb3dSCy Schubert return -1; 2382b15cb3dSCy Schubert } 2392b15cb3dSCy Schubert 2402b15cb3dSCy Schubert link_created = (*pCreateHardLinkA)(linkname, filename, NULL); 2412b15cb3dSCy Schubert 2422b15cb3dSCy Schubert if (link_created) 2432b15cb3dSCy Schubert return 0; 2442b15cb3dSCy Schubert 2452b15cb3dSCy Schubert saved_errno = GetLastError(); /* yes we play loose */ 2462b15cb3dSCy Schubert mfprintf(stderr, "Create hard link %s to %s failed: %m\n", 2472b15cb3dSCy Schubert linkname, filename); 2482b15cb3dSCy Schubert errno = saved_errno; 2492b15cb3dSCy Schubert return -1; 2502b15cb3dSCy Schubert } 2512b15cb3dSCy Schubert 2529c2daa00SOllivier Robert void 2539c2daa00SOllivier Robert InitWin32Sockets() { 2549c2daa00SOllivier Robert WORD wVersionRequested; 2559c2daa00SOllivier Robert WSADATA wsaData; 2569c2daa00SOllivier Robert wVersionRequested = MAKEWORD(2,0); 2579c2daa00SOllivier Robert if (WSAStartup(wVersionRequested, &wsaData)) 2589c2daa00SOllivier Robert { 2592b15cb3dSCy Schubert fprintf(stderr, "No useable winsock.dll\n"); 2609c2daa00SOllivier Robert exit(1); 2619c2daa00SOllivier Robert } 2629c2daa00SOllivier Robert } 2639c2daa00SOllivier Robert #endif /* SYS_WINNT */ 2649c2daa00SOllivier Robert 2652b15cb3dSCy Schubert 2662b15cb3dSCy Schubert /* 2672b15cb3dSCy Schubert * followlink() - replace filename with its target if symlink. 2682b15cb3dSCy Schubert * 269*a466cc55SCy Schubert * readlink() does not null-terminate the result. 2702b15cb3dSCy Schubert */ 2712b15cb3dSCy Schubert void 2722b15cb3dSCy Schubert followlink( 2732b15cb3dSCy Schubert char * fname, 2742b15cb3dSCy Schubert size_t bufsiz 2752b15cb3dSCy Schubert ) 2762b15cb3dSCy Schubert { 277*a466cc55SCy Schubert ssize_t len; 278*a466cc55SCy Schubert char * target; 2792b15cb3dSCy Schubert 280*a466cc55SCy Schubert REQUIRE(bufsiz > 0 && bufsiz <= SSIZE_MAX); 2812b15cb3dSCy Schubert 282*a466cc55SCy Schubert target = emalloc(bufsiz); 283*a466cc55SCy Schubert len = readlink(fname, target, bufsiz); 2842b15cb3dSCy Schubert if (len < 0) { 2852b15cb3dSCy Schubert fname[0] = '\0'; 2862b15cb3dSCy Schubert return; 2872b15cb3dSCy Schubert } 288*a466cc55SCy Schubert if ((size_t)len > bufsiz - 1) 289*a466cc55SCy Schubert len = bufsiz - 1; 290*a466cc55SCy Schubert memcpy(fname, target, len); 2912b15cb3dSCy Schubert fname[len] = '\0'; 292*a466cc55SCy Schubert free(target); 2932b15cb3dSCy Schubert } 2942b15cb3dSCy Schubert 2952b15cb3dSCy Schubert 2969c2daa00SOllivier Robert /* 2979c2daa00SOllivier Robert * Main program 2989c2daa00SOllivier Robert */ 2999c2daa00SOllivier Robert int 3009c2daa00SOllivier Robert main( 3019c2daa00SOllivier Robert int argc, /* command line options */ 3029c2daa00SOllivier Robert char **argv 3039c2daa00SOllivier Robert ) 3049c2daa00SOllivier Robert { 3059c2daa00SOllivier Robert struct timeval tv; /* initialization vector */ 306ea906c41SOllivier Robert int md5key = 0; /* generate MD5 keys */ 3072b15cb3dSCy Schubert int optct; /* option count */ 3082b15cb3dSCy Schubert #ifdef AUTOKEY 3099c2daa00SOllivier Robert X509 *cert = NULL; /* X509 certificate */ 3109c2daa00SOllivier Robert EVP_PKEY *pkey_host = NULL; /* host key */ 3119c2daa00SOllivier Robert EVP_PKEY *pkey_sign = NULL; /* sign key */ 3122b15cb3dSCy Schubert EVP_PKEY *pkey_iffkey = NULL; /* IFF sever keys */ 3132b15cb3dSCy Schubert EVP_PKEY *pkey_gqkey = NULL; /* GQ server keys */ 3142b15cb3dSCy Schubert EVP_PKEY *pkey_mvkey = NULL; /* MV trusted agen keys */ 3152b15cb3dSCy Schubert EVP_PKEY *pkey_mvpar[MVMAX]; /* MV cleient keys */ 3169c2daa00SOllivier Robert int hostkey = 0; /* generate RSA keys */ 3172b15cb3dSCy Schubert int iffkey = 0; /* generate IFF keys */ 3182b15cb3dSCy Schubert int gqkey = 0; /* generate GQ keys */ 3199c2daa00SOllivier Robert int mvkey = 0; /* update MV keys */ 3202b15cb3dSCy Schubert int mvpar = 0; /* generate MV parameters */ 3219c2daa00SOllivier Robert char *sign = NULL; /* sign key */ 3229c2daa00SOllivier Robert EVP_PKEY *pkey = NULL; /* temp key */ 3239c2daa00SOllivier Robert const EVP_MD *ectx; /* EVP digest */ 3249c2daa00SOllivier Robert char pathbuf[MAXFILENAME + 1]; 3259c2daa00SOllivier Robert const char *scheme = NULL; /* digest/signature scheme */ 3262b15cb3dSCy Schubert const char *ciphername = NULL; /* to encrypt priv. key */ 3272b15cb3dSCy Schubert const char *exten = NULL; /* private extension */ 3289c2daa00SOllivier Robert char *grpkey = NULL; /* identity extension */ 3299c2daa00SOllivier Robert int nid; /* X509 digest/signature scheme */ 3309c2daa00SOllivier Robert FILE *fstr = NULL; /* file handle */ 3312b15cb3dSCy Schubert char groupbuf[MAXHOSTNAME + 1]; 332ea906c41SOllivier Robert u_int temp; 3332b15cb3dSCy Schubert BIO * bp; 3342b15cb3dSCy Schubert int i, cnt; 3352b15cb3dSCy Schubert char * ptr; 3362b15cb3dSCy Schubert #endif /* AUTOKEY */ 337f0574f5cSXin LI #ifdef OPENSSL 338f0574f5cSXin LI const char *sslvtext; 339f0574f5cSXin LI int sslvmatch; 340f0574f5cSXin LI #endif /* OPENSSL */ 3412b15cb3dSCy Schubert 3422b15cb3dSCy Schubert progname = argv[0]; 3439c2daa00SOllivier Robert 3449c2daa00SOllivier Robert #ifdef SYS_WINNT 3459c2daa00SOllivier Robert /* Initialize before OpenSSL checks */ 3469c2daa00SOllivier Robert InitWin32Sockets(); 3479c2daa00SOllivier Robert if (!init_randfile()) 3489c2daa00SOllivier Robert fprintf(stderr, "Unable to initialize .rnd file\n"); 3492b15cb3dSCy Schubert ssl_applink(); 3509c2daa00SOllivier Robert #endif 3519c2daa00SOllivier Robert 3529c2daa00SOllivier Robert #ifdef OPENSSL 3532b15cb3dSCy Schubert ssl_check_version(); 3549c2daa00SOllivier Robert #endif /* OPENSSL */ 3559c2daa00SOllivier Robert 3562b15cb3dSCy Schubert ntp_crypto_srandom(); 3572b15cb3dSCy Schubert 3589c2daa00SOllivier Robert /* 3599c2daa00SOllivier Robert * Process options, initialize host name and timestamp. 3602b15cb3dSCy Schubert * gethostname() won't null-terminate if hostname is exactly the 3612b15cb3dSCy Schubert * length provided for the buffer. 3629c2daa00SOllivier Robert */ 3632b15cb3dSCy Schubert gethostname(hostbuf, sizeof(hostbuf) - 1); 3642b15cb3dSCy Schubert hostbuf[COUNTOF(hostbuf) - 1] = '\0'; 3659c2daa00SOllivier Robert hostname = hostbuf; 3662b15cb3dSCy Schubert groupname = hostbuf; 3679c2daa00SOllivier Robert passwd1 = hostbuf; 3682b15cb3dSCy Schubert passwd2 = NULL; 3692b15cb3dSCy Schubert GETTIMEOFDAY(&tv, NULL); 3709c2daa00SOllivier Robert epoch = tv.tv_sec; 3712b15cb3dSCy Schubert fstamp = (u_int)(epoch + JAN_1970); 372ea906c41SOllivier Robert 3732b15cb3dSCy Schubert optct = ntpOptionProcess(&ntp_keygenOptions, argc, argv); 3749034852cSGleb Smirnoff argc -= optct; // Just in case we care later. 3759034852cSGleb Smirnoff argv += optct; // Just in case we care later. 3769c2daa00SOllivier Robert 3775e91a9b7SOllivier Robert #ifdef OPENSSL 378f0574f5cSXin LI sslvtext = OpenSSL_version(OPENSSL_VERSION); 379f0574f5cSXin LI sslvmatch = OpenSSL_version_num() == OPENSSL_VERSION_NUMBER; 380f0574f5cSXin LI if (sslvmatch) 3812b15cb3dSCy Schubert fprintf(stderr, "Using OpenSSL version %s\n", 382f0574f5cSXin LI sslvtext); 3832b15cb3dSCy Schubert else 3842b15cb3dSCy Schubert fprintf(stderr, "Built against OpenSSL %s, using version %s\n", 385f0574f5cSXin LI OPENSSL_VERSION_TEXT, sslvtext); 3862b15cb3dSCy Schubert #endif /* OPENSSL */ 3879c2daa00SOllivier Robert 3882b15cb3dSCy Schubert debug = OPT_VALUE_SET_DEBUG_LEVEL; 3899c2daa00SOllivier Robert 3902b15cb3dSCy Schubert if (HAVE_OPT( MD5KEY )) 3912b15cb3dSCy Schubert md5key++; 3922b15cb3dSCy Schubert #ifdef AUTOKEY 3932b15cb3dSCy Schubert if (HAVE_OPT( PASSWORD )) 3942b15cb3dSCy Schubert passwd1 = estrdup(OPT_ARG( PASSWORD )); 3959c2daa00SOllivier Robert 3962b15cb3dSCy Schubert if (HAVE_OPT( EXPORT_PASSWD )) 3972b15cb3dSCy Schubert passwd2 = estrdup(OPT_ARG( EXPORT_PASSWD )); 3989c2daa00SOllivier Robert 399ea906c41SOllivier Robert if (HAVE_OPT( HOST_KEY )) 4009c2daa00SOllivier Robert hostkey++; 4019c2daa00SOllivier Robert 4022b15cb3dSCy Schubert if (HAVE_OPT( SIGN_KEY )) 4032b15cb3dSCy Schubert sign = estrdup(OPT_ARG( SIGN_KEY )); 4042b15cb3dSCy Schubert 4052b15cb3dSCy Schubert if (HAVE_OPT( GQ_PARAMS )) 4062b15cb3dSCy Schubert gqkey++; 4072b15cb3dSCy Schubert 408ea906c41SOllivier Robert if (HAVE_OPT( IFFKEY )) 4099c2daa00SOllivier Robert iffkey++; 410ea906c41SOllivier Robert 4112b15cb3dSCy Schubert if (HAVE_OPT( MV_PARAMS )) { 4122b15cb3dSCy Schubert mvkey++; 4132b15cb3dSCy Schubert nkeys = OPT_VALUE_MV_PARAMS; 4142b15cb3dSCy Schubert } 4152b15cb3dSCy Schubert if (HAVE_OPT( MV_KEYS )) { 4162b15cb3dSCy Schubert mvpar++; 4172b15cb3dSCy Schubert nkeys = OPT_VALUE_MV_KEYS; 4182b15cb3dSCy Schubert } 4199c2daa00SOllivier Robert 4202b15cb3dSCy Schubert if (HAVE_OPT( IMBITS )) 4212b15cb3dSCy Schubert modulus2 = OPT_VALUE_IMBITS; 4229c2daa00SOllivier Robert 423ea906c41SOllivier Robert if (HAVE_OPT( MODULUS )) 424ea906c41SOllivier Robert modulus = OPT_VALUE_MODULUS; 4259c2daa00SOllivier Robert 4262b15cb3dSCy Schubert if (HAVE_OPT( CERTIFICATE )) 4272b15cb3dSCy Schubert scheme = OPT_ARG( CERTIFICATE ); 4282b15cb3dSCy Schubert 4292b15cb3dSCy Schubert if (HAVE_OPT( CIPHER )) 4302b15cb3dSCy Schubert ciphername = OPT_ARG( CIPHER ); 4312b15cb3dSCy Schubert 4322b15cb3dSCy Schubert if (HAVE_OPT( SUBJECT_NAME )) 4332b15cb3dSCy Schubert hostname = estrdup(OPT_ARG( SUBJECT_NAME )); 4342b15cb3dSCy Schubert 4352b15cb3dSCy Schubert if (HAVE_OPT( IDENT )) 4362b15cb3dSCy Schubert groupname = estrdup(OPT_ARG( IDENT )); 4372b15cb3dSCy Schubert 4382b15cb3dSCy Schubert if (HAVE_OPT( LIFETIME )) 4392b15cb3dSCy Schubert lifetime = OPT_VALUE_LIFETIME; 4402b15cb3dSCy Schubert 441ea906c41SOllivier Robert if (HAVE_OPT( PVT_CERT )) 4429c2daa00SOllivier Robert exten = EXT_KEY_PRIVATE; 4439c2daa00SOllivier Robert 444ea906c41SOllivier Robert if (HAVE_OPT( TRUSTED_CERT )) 4459c2daa00SOllivier Robert exten = EXT_KEY_TRUST; 4469c2daa00SOllivier Robert 4472b15cb3dSCy Schubert /* 4482b15cb3dSCy Schubert * Remove the group name from the hostname variable used 4492b15cb3dSCy Schubert * in host and sign certificate file names. 4502b15cb3dSCy Schubert */ 4512b15cb3dSCy Schubert if (hostname != hostbuf) 4522b15cb3dSCy Schubert ptr = strchr(hostname, '@'); 4532b15cb3dSCy Schubert else 4542b15cb3dSCy Schubert ptr = NULL; 4552b15cb3dSCy Schubert if (ptr != NULL) { 4562b15cb3dSCy Schubert *ptr = '\0'; 4572b15cb3dSCy Schubert groupname = estrdup(ptr + 1); 4582b15cb3dSCy Schubert /* -s @group is equivalent to -i group, host unch. */ 4592b15cb3dSCy Schubert if (ptr == hostname) 4602b15cb3dSCy Schubert hostname = hostbuf; 461ea906c41SOllivier Robert } 4629c2daa00SOllivier Robert 4632b15cb3dSCy Schubert /* 4642b15cb3dSCy Schubert * Derive host certificate issuer/subject names from host name 4652b15cb3dSCy Schubert * and optional group. If no groupname is provided, the issuer 4662b15cb3dSCy Schubert * and subject is the hostname with no '@group', and the 4672b15cb3dSCy Schubert * groupname variable is pointed to hostname for use in IFF, GQ, 4682b15cb3dSCy Schubert * and MV parameters file names. 4692b15cb3dSCy Schubert */ 4702b15cb3dSCy Schubert if (groupname == hostbuf) { 4712b15cb3dSCy Schubert certname = hostname; 4722b15cb3dSCy Schubert } else { 4732b15cb3dSCy Schubert snprintf(certnamebuf, sizeof(certnamebuf), "%s@%s", 4742b15cb3dSCy Schubert hostname, groupname); 4752b15cb3dSCy Schubert certname = certnamebuf; 476ea906c41SOllivier Robert } 4779c2daa00SOllivier Robert 4789c2daa00SOllivier Robert /* 4799c2daa00SOllivier Robert * Seed random number generator and grow weeds. 4809c2daa00SOllivier Robert */ 481f0574f5cSXin LI #if OPENSSL_VERSION_NUMBER < 0x10100000L 4829c2daa00SOllivier Robert ERR_load_crypto_strings(); 4839c2daa00SOllivier Robert OpenSSL_add_all_algorithms(); 484f0574f5cSXin LI #endif /* OPENSSL_VERSION_NUMBER */ 4852b15cb3dSCy Schubert if (!RAND_status()) { 4862b15cb3dSCy Schubert if (RAND_file_name(pathbuf, sizeof(pathbuf)) == NULL) { 4879c2daa00SOllivier Robert fprintf(stderr, "RAND_file_name %s\n", 4889c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 4892b15cb3dSCy Schubert exit (-1); 4909c2daa00SOllivier Robert } 4919c2daa00SOllivier Robert temp = RAND_load_file(pathbuf, -1); 4929c2daa00SOllivier Robert if (temp == 0) { 4939c2daa00SOllivier Robert fprintf(stderr, 4942b15cb3dSCy Schubert "RAND_load_file %s not found or empty\n", 4952b15cb3dSCy Schubert pathbuf); 4962b15cb3dSCy Schubert exit (-1); 4979c2daa00SOllivier Robert } 4989c2daa00SOllivier Robert fprintf(stderr, 4999c2daa00SOllivier Robert "Random seed file %s %u bytes\n", pathbuf, temp); 5009c2daa00SOllivier Robert RAND_add(&epoch, sizeof(epoch), 4.0); 5012b15cb3dSCy Schubert } 5022b15cb3dSCy Schubert #endif /* AUTOKEY */ 5039c2daa00SOllivier Robert 5049c2daa00SOllivier Robert /* 5052b15cb3dSCy Schubert * Create new unencrypted MD5 keys file if requested. If this 5062b15cb3dSCy Schubert * option is selected, ignore all other options. 5079c2daa00SOllivier Robert */ 5082b15cb3dSCy Schubert if (md5key) { 5092b15cb3dSCy Schubert gen_md5("md5"); 5102b15cb3dSCy Schubert exit (0); 5112b15cb3dSCy Schubert } 5129c2daa00SOllivier Robert 5132b15cb3dSCy Schubert #ifdef AUTOKEY 5149c2daa00SOllivier Robert /* 5152b15cb3dSCy Schubert * Load previous certificate if available. 5169c2daa00SOllivier Robert */ 5172b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_cert_%s", hostname); 5189c2daa00SOllivier Robert if ((fstr = fopen(filename, "r")) != NULL) { 5199c2daa00SOllivier Robert cert = PEM_read_X509(fstr, NULL, NULL, NULL); 5209c2daa00SOllivier Robert fclose(fstr); 5212b15cb3dSCy Schubert } 5222b15cb3dSCy Schubert if (cert != NULL) { 5232b15cb3dSCy Schubert 5242b15cb3dSCy Schubert /* 5252b15cb3dSCy Schubert * Extract subject name. 5262b15cb3dSCy Schubert */ 5272b15cb3dSCy Schubert X509_NAME_oneline(X509_get_subject_name(cert), groupbuf, 5282b15cb3dSCy Schubert MAXFILENAME); 5292b15cb3dSCy Schubert 5302b15cb3dSCy Schubert /* 5312b15cb3dSCy Schubert * Extract digest/signature scheme. 5322b15cb3dSCy Schubert */ 5332b15cb3dSCy Schubert if (scheme == NULL) { 534f391d6bcSXin LI nid = X509_get_signature_nid(cert); 5359c2daa00SOllivier Robert scheme = OBJ_nid2sn(nid); 5362b15cb3dSCy Schubert } 5372b15cb3dSCy Schubert 5382b15cb3dSCy Schubert /* 5392b15cb3dSCy Schubert * If a key_usage extension field is present, determine 5402b15cb3dSCy Schubert * whether this is a trusted or private certificate. 5412b15cb3dSCy Schubert */ 5422b15cb3dSCy Schubert if (exten == NULL) { 5432b15cb3dSCy Schubert ptr = strstr(groupbuf, "CN="); 5442b15cb3dSCy Schubert cnt = X509_get_ext_count(cert); 5452b15cb3dSCy Schubert for (i = 0; i < cnt; i++) { 546f391d6bcSXin LI X509_EXTENSION *ext; 547f391d6bcSXin LI ASN1_OBJECT *obj; 548f391d6bcSXin LI 5492b15cb3dSCy Schubert ext = X509_get_ext(cert, i); 550f391d6bcSXin LI obj = X509_EXTENSION_get_object(ext); 551f391d6bcSXin LI 552f391d6bcSXin LI if (OBJ_obj2nid(obj) == 5532b15cb3dSCy Schubert NID_ext_key_usage) { 5542b15cb3dSCy Schubert bp = BIO_new(BIO_s_mem()); 5552b15cb3dSCy Schubert X509V3_EXT_print(bp, ext, 0, 0); 5562b15cb3dSCy Schubert BIO_gets(bp, pathbuf, 5572b15cb3dSCy Schubert MAXFILENAME); 5582b15cb3dSCy Schubert BIO_free(bp); 5592b15cb3dSCy Schubert if (strcmp(pathbuf, 5602b15cb3dSCy Schubert "Trust Root") == 0) 5612b15cb3dSCy Schubert exten = EXT_KEY_TRUST; 5622b15cb3dSCy Schubert else if (strcmp(pathbuf, 5632b15cb3dSCy Schubert "Private") == 0) 5642b15cb3dSCy Schubert exten = EXT_KEY_PRIVATE; 5652b15cb3dSCy Schubert certname = estrdup(ptr + 3); 5669c2daa00SOllivier Robert } 5679c2daa00SOllivier Robert } 5682b15cb3dSCy Schubert } 5692b15cb3dSCy Schubert } 5702b15cb3dSCy Schubert if (scheme == NULL) 5719c2daa00SOllivier Robert scheme = "RSA-MD5"; 5722b15cb3dSCy Schubert if (ciphername == NULL) 5732b15cb3dSCy Schubert ciphername = "des-ede3-cbc"; 5742b15cb3dSCy Schubert cipher = EVP_get_cipherbyname(ciphername); 5752b15cb3dSCy Schubert if (cipher == NULL) { 5762b15cb3dSCy Schubert fprintf(stderr, "Unknown cipher %s\n", ciphername); 5772b15cb3dSCy Schubert exit(-1); 5789c2daa00SOllivier Robert } 5792b15cb3dSCy Schubert fprintf(stderr, "Using host %s group %s\n", hostname, 5802b15cb3dSCy Schubert groupname); 5812b15cb3dSCy Schubert 5822b15cb3dSCy Schubert /* 5832b15cb3dSCy Schubert * Create a new encrypted RSA host key file if requested; 5842b15cb3dSCy Schubert * otherwise, look for an existing host key file. If not found, 5852b15cb3dSCy Schubert * create a new encrypted RSA host key file. If that fails, go 5862b15cb3dSCy Schubert * no further. 5872b15cb3dSCy Schubert */ 5882b15cb3dSCy Schubert if (hostkey) 5892b15cb3dSCy Schubert pkey_host = genkey("RSA", "host"); 5902b15cb3dSCy Schubert if (pkey_host == NULL) { 5912b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_host_%s", hostname); 5922b15cb3dSCy Schubert pkey_host = readkey(filename, passwd1, &fstamp, NULL); 5932b15cb3dSCy Schubert if (pkey_host != NULL) { 5942b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 5952b15cb3dSCy Schubert fprintf(stderr, "Using host key %s\n", 5962b15cb3dSCy Schubert filename); 5972b15cb3dSCy Schubert } else { 5982b15cb3dSCy Schubert pkey_host = genkey("RSA", "host"); 5992b15cb3dSCy Schubert } 6002b15cb3dSCy Schubert } 6012b15cb3dSCy Schubert if (pkey_host == NULL) { 6022b15cb3dSCy Schubert fprintf(stderr, "Generating host key fails\n"); 6032b15cb3dSCy Schubert exit(-1); 6042b15cb3dSCy Schubert } 6052b15cb3dSCy Schubert 6062b15cb3dSCy Schubert /* 6072b15cb3dSCy Schubert * Create new encrypted RSA or DSA sign keys file if requested; 6082b15cb3dSCy Schubert * otherwise, look for an existing sign key file. If not found, 6092b15cb3dSCy Schubert * use the host key instead. 6102b15cb3dSCy Schubert */ 6112b15cb3dSCy Schubert if (sign != NULL) 6122b15cb3dSCy Schubert pkey_sign = genkey(sign, "sign"); 6132b15cb3dSCy Schubert if (pkey_sign == NULL) { 6142b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_sign_%s", 6152b15cb3dSCy Schubert hostname); 6162b15cb3dSCy Schubert pkey_sign = readkey(filename, passwd1, &fstamp, NULL); 6172b15cb3dSCy Schubert if (pkey_sign != NULL) { 6182b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 6192b15cb3dSCy Schubert fprintf(stderr, "Using sign key %s\n", 6202b15cb3dSCy Schubert filename); 6212b15cb3dSCy Schubert } else { 6222b15cb3dSCy Schubert pkey_sign = pkey_host; 6232b15cb3dSCy Schubert fprintf(stderr, "Using host key as sign key\n"); 6242b15cb3dSCy Schubert } 6252b15cb3dSCy Schubert } 6262b15cb3dSCy Schubert 6272b15cb3dSCy Schubert /* 6282b15cb3dSCy Schubert * Create new encrypted GQ server keys file if requested; 6292b15cb3dSCy Schubert * otherwise, look for an exisiting file. If found, fetch the 6302b15cb3dSCy Schubert * public key for the certificate. 6312b15cb3dSCy Schubert */ 6322b15cb3dSCy Schubert if (gqkey) 6332b15cb3dSCy Schubert pkey_gqkey = gen_gqkey("gqkey"); 6342b15cb3dSCy Schubert if (pkey_gqkey == NULL) { 6352b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_gqkey_%s", 6362b15cb3dSCy Schubert groupname); 6372b15cb3dSCy Schubert pkey_gqkey = readkey(filename, passwd1, &fstamp, NULL); 6382b15cb3dSCy Schubert if (pkey_gqkey != NULL) { 6392b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 6402b15cb3dSCy Schubert fprintf(stderr, "Using GQ parameters %s\n", 6412b15cb3dSCy Schubert filename); 6422b15cb3dSCy Schubert } 6432b15cb3dSCy Schubert } 644f391d6bcSXin LI if (pkey_gqkey != NULL) { 645f391d6bcSXin LI RSA *rsa; 646f391d6bcSXin LI const BIGNUM *q; 647f391d6bcSXin LI 648f391d6bcSXin LI rsa = EVP_PKEY_get0_RSA(pkey_gqkey); 649f391d6bcSXin LI RSA_get0_factors(rsa, NULL, &q); 650f391d6bcSXin LI grpkey = BN_bn2hex(q); 651f391d6bcSXin LI } 6522b15cb3dSCy Schubert 6532b15cb3dSCy Schubert /* 6542b15cb3dSCy Schubert * Write the nonencrypted GQ client parameters to the stdout 6552b15cb3dSCy Schubert * stream. The parameter file is the server key file with the 6562b15cb3dSCy Schubert * private key obscured. 6572b15cb3dSCy Schubert */ 6582b15cb3dSCy Schubert if (pkey_gqkey != NULL && HAVE_OPT(ID_KEY)) { 6592b15cb3dSCy Schubert RSA *rsa; 6602b15cb3dSCy Schubert 6612b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 6622b15cb3dSCy Schubert "ntpkey_gqpar_%s.%u", groupname, fstamp); 6632b15cb3dSCy Schubert fprintf(stderr, "Writing GQ parameters %s to stdout\n", 6642b15cb3dSCy Schubert filename); 6652b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 6662b15cb3dSCy Schubert ctime(&epoch)); 667f391d6bcSXin LI /* XXX: This modifies the private key and should probably use a 668f391d6bcSXin LI * copy of it instead. */ 669f391d6bcSXin LI rsa = EVP_PKEY_get0_RSA(pkey_gqkey); 670f391d6bcSXin LI RSA_set0_factors(rsa, BN_dup(BN_value_one()), BN_dup(BN_value_one())); 6712b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 6722b15cb3dSCy Schubert EVP_PKEY_assign_RSA(pkey, rsa); 6732b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 6742b15cb3dSCy Schubert NULL, NULL); 6752b15cb3dSCy Schubert fflush(stdout); 6762b15cb3dSCy Schubert if (debug) 6772b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 6782b15cb3dSCy Schubert } 6792b15cb3dSCy Schubert 6802b15cb3dSCy Schubert /* 6812b15cb3dSCy Schubert * Write the encrypted GQ server keys to the stdout stream. 6822b15cb3dSCy Schubert */ 6832b15cb3dSCy Schubert if (pkey_gqkey != NULL && passwd2 != NULL) { 6842b15cb3dSCy Schubert RSA *rsa; 6852b15cb3dSCy Schubert 6862b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 6872b15cb3dSCy Schubert "ntpkey_gqkey_%s.%u", groupname, fstamp); 6882b15cb3dSCy Schubert fprintf(stderr, "Writing GQ keys %s to stdout\n", 6892b15cb3dSCy Schubert filename); 6902b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 6912b15cb3dSCy Schubert ctime(&epoch)); 692f391d6bcSXin LI rsa = EVP_PKEY_get0_RSA(pkey_gqkey); 6932b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 6942b15cb3dSCy Schubert EVP_PKEY_assign_RSA(pkey, rsa); 6952b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 6962b15cb3dSCy Schubert NULL, passwd2); 6972b15cb3dSCy Schubert fflush(stdout); 6982b15cb3dSCy Schubert if (debug) 6992b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 7002b15cb3dSCy Schubert } 7012b15cb3dSCy Schubert 7022b15cb3dSCy Schubert /* 7032b15cb3dSCy Schubert * Create new encrypted IFF server keys file if requested; 7042b15cb3dSCy Schubert * otherwise, look for existing file. 7052b15cb3dSCy Schubert */ 7062b15cb3dSCy Schubert if (iffkey) 7072b15cb3dSCy Schubert pkey_iffkey = gen_iffkey("iffkey"); 7082b15cb3dSCy Schubert if (pkey_iffkey == NULL) { 7092b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_iffkey_%s", 7102b15cb3dSCy Schubert groupname); 7112b15cb3dSCy Schubert pkey_iffkey = readkey(filename, passwd1, &fstamp, NULL); 7122b15cb3dSCy Schubert if (pkey_iffkey != NULL) { 7132b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 7142b15cb3dSCy Schubert fprintf(stderr, "Using IFF keys %s\n", 7152b15cb3dSCy Schubert filename); 7162b15cb3dSCy Schubert } 7172b15cb3dSCy Schubert } 7182b15cb3dSCy Schubert 7192b15cb3dSCy Schubert /* 7202b15cb3dSCy Schubert * Write the nonencrypted IFF client parameters to the stdout 7212b15cb3dSCy Schubert * stream. The parameter file is the server key file with the 7222b15cb3dSCy Schubert * private key obscured. 7232b15cb3dSCy Schubert */ 7242b15cb3dSCy Schubert if (pkey_iffkey != NULL && HAVE_OPT(ID_KEY)) { 7252b15cb3dSCy Schubert DSA *dsa; 7262b15cb3dSCy Schubert 7272b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7282b15cb3dSCy Schubert "ntpkey_iffpar_%s.%u", groupname, fstamp); 7292b15cb3dSCy Schubert fprintf(stderr, "Writing IFF parameters %s to stdout\n", 7302b15cb3dSCy Schubert filename); 7312b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7322b15cb3dSCy Schubert ctime(&epoch)); 733f391d6bcSXin LI /* XXX: This modifies the private key and should probably use a 734f391d6bcSXin LI * copy of it instead. */ 735f391d6bcSXin LI dsa = EVP_PKEY_get0_DSA(pkey_iffkey); 736f391d6bcSXin LI DSA_set0_key(dsa, NULL, BN_dup(BN_value_one())); 7372b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 7382b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey, dsa); 7392b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 7402b15cb3dSCy Schubert NULL, NULL); 7412b15cb3dSCy Schubert fflush(stdout); 7422b15cb3dSCy Schubert if (debug) 7432b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 7442b15cb3dSCy Schubert } 7452b15cb3dSCy Schubert 7462b15cb3dSCy Schubert /* 7472b15cb3dSCy Schubert * Write the encrypted IFF server keys to the stdout stream. 7482b15cb3dSCy Schubert */ 7492b15cb3dSCy Schubert if (pkey_iffkey != NULL && passwd2 != NULL) { 7502b15cb3dSCy Schubert DSA *dsa; 7512b15cb3dSCy Schubert 7522b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7532b15cb3dSCy Schubert "ntpkey_iffkey_%s.%u", groupname, fstamp); 7542b15cb3dSCy Schubert fprintf(stderr, "Writing IFF keys %s to stdout\n", 7552b15cb3dSCy Schubert filename); 7562b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7572b15cb3dSCy Schubert ctime(&epoch)); 758f391d6bcSXin LI dsa = EVP_PKEY_get0_DSA(pkey_iffkey); 7592b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 7602b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey, dsa); 7612b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 7622b15cb3dSCy Schubert NULL, passwd2); 7632b15cb3dSCy Schubert fflush(stdout); 7642b15cb3dSCy Schubert if (debug) 7652b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 7662b15cb3dSCy Schubert } 7672b15cb3dSCy Schubert 7682b15cb3dSCy Schubert /* 7692b15cb3dSCy Schubert * Create new encrypted MV trusted-authority keys file if 7702b15cb3dSCy Schubert * requested; otherwise, look for existing keys file. 7712b15cb3dSCy Schubert */ 7722b15cb3dSCy Schubert if (mvkey) 7732b15cb3dSCy Schubert pkey_mvkey = gen_mvkey("mv", pkey_mvpar); 7742b15cb3dSCy Schubert if (pkey_mvkey == NULL) { 7752b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_mvta_%s", 7762b15cb3dSCy Schubert groupname); 7772b15cb3dSCy Schubert pkey_mvkey = readkey(filename, passwd1, &fstamp, 7782b15cb3dSCy Schubert pkey_mvpar); 7792b15cb3dSCy Schubert if (pkey_mvkey != NULL) { 7802b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 7812b15cb3dSCy Schubert fprintf(stderr, "Using MV keys %s\n", 7822b15cb3dSCy Schubert filename); 7832b15cb3dSCy Schubert } 7842b15cb3dSCy Schubert } 7852b15cb3dSCy Schubert 7862b15cb3dSCy Schubert /* 7872b15cb3dSCy Schubert * Write the nonencrypted MV client parameters to the stdout 7882b15cb3dSCy Schubert * stream. For the moment, we always use the client parameters 7892b15cb3dSCy Schubert * associated with client key 1. 7902b15cb3dSCy Schubert */ 7912b15cb3dSCy Schubert if (pkey_mvkey != NULL && HAVE_OPT(ID_KEY)) { 7922b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7932b15cb3dSCy Schubert "ntpkey_mvpar_%s.%u", groupname, fstamp); 7942b15cb3dSCy Schubert fprintf(stderr, "Writing MV parameters %s to stdout\n", 7952b15cb3dSCy Schubert filename); 7962b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7972b15cb3dSCy Schubert ctime(&epoch)); 7982b15cb3dSCy Schubert pkey = pkey_mvpar[2]; 7992b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 8002b15cb3dSCy Schubert NULL, NULL); 8012b15cb3dSCy Schubert fflush(stdout); 8022b15cb3dSCy Schubert if (debug) 803f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(pkey), 0); 8042b15cb3dSCy Schubert } 8052b15cb3dSCy Schubert 8062b15cb3dSCy Schubert /* 8072b15cb3dSCy Schubert * Write the encrypted MV server keys to the stdout stream. 8082b15cb3dSCy Schubert */ 8092b15cb3dSCy Schubert if (pkey_mvkey != NULL && passwd2 != NULL) { 8102b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 8112b15cb3dSCy Schubert "ntpkey_mvkey_%s.%u", groupname, fstamp); 8122b15cb3dSCy Schubert fprintf(stderr, "Writing MV keys %s to stdout\n", 8132b15cb3dSCy Schubert filename); 8142b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 8152b15cb3dSCy Schubert ctime(&epoch)); 8162b15cb3dSCy Schubert pkey = pkey_mvpar[1]; 8172b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 8182b15cb3dSCy Schubert NULL, passwd2); 8192b15cb3dSCy Schubert fflush(stdout); 8202b15cb3dSCy Schubert if (debug) 821f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(pkey), 0); 8222b15cb3dSCy Schubert } 8232b15cb3dSCy Schubert 8242b15cb3dSCy Schubert /* 8252b15cb3dSCy Schubert * Decode the digest/signature scheme and create the 8262b15cb3dSCy Schubert * certificate. Do this every time we run the program. 8272b15cb3dSCy Schubert */ 8289c2daa00SOllivier Robert ectx = EVP_get_digestbyname(scheme); 8299c2daa00SOllivier Robert if (ectx == NULL) { 8309c2daa00SOllivier Robert fprintf(stderr, 8319c2daa00SOllivier Robert "Invalid digest/signature combination %s\n", 8329c2daa00SOllivier Robert scheme); 8332b15cb3dSCy Schubert exit (-1); 8349c2daa00SOllivier Robert } 8352b15cb3dSCy Schubert x509(pkey_sign, ectx, grpkey, exten, certname); 8362b15cb3dSCy Schubert #endif /* AUTOKEY */ 8372b15cb3dSCy Schubert exit(0); 8389c2daa00SOllivier Robert } 8399c2daa00SOllivier Robert 8402b15cb3dSCy Schubert 8419c2daa00SOllivier Robert /* 8422b15cb3dSCy Schubert * Generate semi-random MD5 keys compatible with NTPv3 and NTPv4. Also, 8432b15cb3dSCy Schubert * if OpenSSL is around, generate random SHA1 keys compatible with 8442b15cb3dSCy Schubert * symmetric key cryptography. 8459c2daa00SOllivier Robert */ 8469c2daa00SOllivier Robert int 8479c2daa00SOllivier Robert gen_md5( 8482b15cb3dSCy Schubert const char *id /* file name id */ 8499c2daa00SOllivier Robert ) 8509c2daa00SOllivier Robert { 8512b15cb3dSCy Schubert u_char md5key[MD5SIZE + 1]; /* MD5 key */ 8529c2daa00SOllivier Robert FILE *str; 8539c2daa00SOllivier Robert int i, j; 8542b15cb3dSCy Schubert #ifdef OPENSSL 8552b15cb3dSCy Schubert u_char keystr[MD5SIZE]; 8562b15cb3dSCy Schubert u_char hexstr[2 * MD5SIZE + 1]; 8572b15cb3dSCy Schubert u_char hex[] = "0123456789abcdef"; 8582b15cb3dSCy Schubert #endif /* OPENSSL */ 8599c2daa00SOllivier Robert 8602b15cb3dSCy Schubert str = fheader("MD5key", id, groupname); 8619c2daa00SOllivier Robert for (i = 1; i <= MD5KEYS; i++) { 8622b15cb3dSCy Schubert for (j = 0; j < MD5SIZE; j++) { 863a25439b6SCy Schubert u_char temp; 8642b15cb3dSCy Schubert 8659c2daa00SOllivier Robert while (1) { 8662b15cb3dSCy Schubert int rc; 8672b15cb3dSCy Schubert 868a25439b6SCy Schubert rc = ntp_crypto_random_buf( 869a25439b6SCy Schubert &temp, sizeof(temp)); 8702b15cb3dSCy Schubert if (-1 == rc) { 8712b15cb3dSCy Schubert fprintf(stderr, "ntp_crypto_random_buf() failed.\n"); 8722b15cb3dSCy Schubert exit (-1); 8732b15cb3dSCy Schubert } 8749c2daa00SOllivier Robert if (temp == '#') 8759c2daa00SOllivier Robert continue; 8762b15cb3dSCy Schubert 8779c2daa00SOllivier Robert if (temp > 0x20 && temp < 0x7f) 8789c2daa00SOllivier Robert break; 8799c2daa00SOllivier Robert } 880a25439b6SCy Schubert md5key[j] = temp; 8819c2daa00SOllivier Robert } 8822b15cb3dSCy Schubert md5key[j] = '\0'; 8832b15cb3dSCy Schubert fprintf(str, "%2d MD5 %s # MD5 key\n", i, 8849c2daa00SOllivier Robert md5key); 8859c2daa00SOllivier Robert } 8862b15cb3dSCy Schubert #ifdef OPENSSL 8872b15cb3dSCy Schubert for (i = 1; i <= MD5KEYS; i++) { 8882b15cb3dSCy Schubert RAND_bytes(keystr, 20); 8892b15cb3dSCy Schubert for (j = 0; j < MD5SIZE; j++) { 8902b15cb3dSCy Schubert hexstr[2 * j] = hex[keystr[j] >> 4]; 8912b15cb3dSCy Schubert hexstr[2 * j + 1] = hex[keystr[j] & 0xf]; 8922b15cb3dSCy Schubert } 8932b15cb3dSCy Schubert hexstr[2 * MD5SIZE] = '\0'; 8942b15cb3dSCy Schubert fprintf(str, "%2d SHA1 %s # SHA1 key\n", i + MD5KEYS, 8952b15cb3dSCy Schubert hexstr); 8969c2daa00SOllivier Robert } 8979c2daa00SOllivier Robert #endif /* OPENSSL */ 8982b15cb3dSCy Schubert fclose(str); 8992b15cb3dSCy Schubert return (1); 9002b15cb3dSCy Schubert } 9019c2daa00SOllivier Robert 9029c2daa00SOllivier Robert 9032b15cb3dSCy Schubert #ifdef AUTOKEY 9042b15cb3dSCy Schubert /* 9052b15cb3dSCy Schubert * readkey - load cryptographic parameters and keys 9062b15cb3dSCy Schubert * 9072b15cb3dSCy Schubert * This routine loads a PEM-encoded file of given name and password and 9082b15cb3dSCy Schubert * extracts the filestamp from the file name. It returns a pointer to 9092b15cb3dSCy Schubert * the first key if valid, NULL if not. 9102b15cb3dSCy Schubert */ 9112b15cb3dSCy Schubert EVP_PKEY * /* public/private key pair */ 9122b15cb3dSCy Schubert readkey( 9132b15cb3dSCy Schubert char *cp, /* file name */ 9142b15cb3dSCy Schubert char *passwd, /* password */ 9152b15cb3dSCy Schubert u_int *estamp, /* file stamp */ 9162b15cb3dSCy Schubert EVP_PKEY **evpars /* parameter list pointer */ 9172b15cb3dSCy Schubert ) 9182b15cb3dSCy Schubert { 9192b15cb3dSCy Schubert FILE *str; /* file handle */ 9202b15cb3dSCy Schubert EVP_PKEY *pkey = NULL; /* public/private key */ 9212b15cb3dSCy Schubert u_int gstamp; /* filestamp */ 9222b15cb3dSCy Schubert char linkname[MAXFILENAME]; /* filestamp buffer) */ 9232b15cb3dSCy Schubert EVP_PKEY *parkey; 9242b15cb3dSCy Schubert char *ptr; 9252b15cb3dSCy Schubert int i; 9262b15cb3dSCy Schubert 9272b15cb3dSCy Schubert /* 9282b15cb3dSCy Schubert * Open the key file. 9292b15cb3dSCy Schubert */ 9302b15cb3dSCy Schubert str = fopen(cp, "r"); 9312b15cb3dSCy Schubert if (str == NULL) 9322b15cb3dSCy Schubert return (NULL); 9332b15cb3dSCy Schubert 9342b15cb3dSCy Schubert /* 9352b15cb3dSCy Schubert * Read the filestamp, which is contained in the first line. 9362b15cb3dSCy Schubert */ 9372b15cb3dSCy Schubert if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) { 9382b15cb3dSCy Schubert fprintf(stderr, "Empty key file %s\n", cp); 9392b15cb3dSCy Schubert fclose(str); 9402b15cb3dSCy Schubert return (NULL); 9412b15cb3dSCy Schubert } 9422b15cb3dSCy Schubert if ((ptr = strrchr(ptr, '.')) == NULL) { 9432b15cb3dSCy Schubert fprintf(stderr, "No filestamp found in %s\n", cp); 9442b15cb3dSCy Schubert fclose(str); 9452b15cb3dSCy Schubert return (NULL); 9462b15cb3dSCy Schubert } 9472b15cb3dSCy Schubert if (sscanf(++ptr, "%u", &gstamp) != 1) { 9482b15cb3dSCy Schubert fprintf(stderr, "Invalid filestamp found in %s\n", cp); 9492b15cb3dSCy Schubert fclose(str); 9502b15cb3dSCy Schubert return (NULL); 9512b15cb3dSCy Schubert } 9522b15cb3dSCy Schubert 9532b15cb3dSCy Schubert /* 9542b15cb3dSCy Schubert * Read and decrypt PEM-encoded private keys. The first one 9552b15cb3dSCy Schubert * found is returned. If others are expected, add them to the 9562b15cb3dSCy Schubert * parameter list. 9572b15cb3dSCy Schubert */ 9582b15cb3dSCy Schubert for (i = 0; i <= MVMAX - 1;) { 9592b15cb3dSCy Schubert parkey = PEM_read_PrivateKey(str, NULL, NULL, passwd); 9602b15cb3dSCy Schubert if (evpars != NULL) { 9612b15cb3dSCy Schubert evpars[i++] = parkey; 9622b15cb3dSCy Schubert evpars[i] = NULL; 9632b15cb3dSCy Schubert } 9642b15cb3dSCy Schubert if (parkey == NULL) 9652b15cb3dSCy Schubert break; 9662b15cb3dSCy Schubert 9672b15cb3dSCy Schubert if (pkey == NULL) 9682b15cb3dSCy Schubert pkey = parkey; 9692b15cb3dSCy Schubert if (debug) { 970f391d6bcSXin LI if (EVP_PKEY_base_id(parkey) == EVP_PKEY_DSA) 971f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(parkey), 9722b15cb3dSCy Schubert 0); 973f391d6bcSXin LI else if (EVP_PKEY_base_id(parkey) == EVP_PKEY_RSA) 974f391d6bcSXin LI RSA_print_fp(stderr, EVP_PKEY_get0_RSA(parkey), 9752b15cb3dSCy Schubert 0); 9762b15cb3dSCy Schubert } 9772b15cb3dSCy Schubert } 9782b15cb3dSCy Schubert fclose(str); 9792b15cb3dSCy Schubert if (pkey == NULL) { 9802b15cb3dSCy Schubert fprintf(stderr, "Corrupt file %s or wrong key %s\n%s\n", 9812b15cb3dSCy Schubert cp, passwd, ERR_error_string(ERR_get_error(), 9822b15cb3dSCy Schubert NULL)); 9832b15cb3dSCy Schubert exit (-1); 9842b15cb3dSCy Schubert } 9852b15cb3dSCy Schubert *estamp = gstamp; 9862b15cb3dSCy Schubert return (pkey); 9872b15cb3dSCy Schubert } 9882b15cb3dSCy Schubert 9892b15cb3dSCy Schubert 9909c2daa00SOllivier Robert /* 9919c2daa00SOllivier Robert * Generate RSA public/private key pair 9929c2daa00SOllivier Robert */ 9939c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 9949c2daa00SOllivier Robert gen_rsa( 9952b15cb3dSCy Schubert const char *id /* file name id */ 9969c2daa00SOllivier Robert ) 9979c2daa00SOllivier Robert { 9989c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 9999c2daa00SOllivier Robert RSA *rsa; /* RSA parameters and key pair */ 10009c2daa00SOllivier Robert FILE *str; 10019c2daa00SOllivier Robert 10029c2daa00SOllivier Robert fprintf(stderr, "Generating RSA keys (%d bits)...\n", modulus); 1003f391d6bcSXin LI rsa = genRsaKeyPair(modulus, _UC("RSA")); 10049c2daa00SOllivier Robert fprintf(stderr, "\n"); 10059c2daa00SOllivier Robert if (rsa == NULL) { 10069c2daa00SOllivier Robert fprintf(stderr, "RSA generate keys fails\n%s\n", 10079c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10089c2daa00SOllivier Robert return (NULL); 10099c2daa00SOllivier Robert } 10109c2daa00SOllivier Robert 10119c2daa00SOllivier Robert /* 10129c2daa00SOllivier Robert * For signature encryption it is not necessary that the RSA 10139c2daa00SOllivier Robert * parameters be strictly groomed and once in a while the 10149c2daa00SOllivier Robert * modulus turns out to be non-prime. Just for grins, we check 10159c2daa00SOllivier Robert * the primality. 10169c2daa00SOllivier Robert */ 10179c2daa00SOllivier Robert if (!RSA_check_key(rsa)) { 10189c2daa00SOllivier Robert fprintf(stderr, "Invalid RSA key\n%s\n", 10199c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10209c2daa00SOllivier Robert RSA_free(rsa); 10219c2daa00SOllivier Robert return (NULL); 10229c2daa00SOllivier Robert } 10239c2daa00SOllivier Robert 10249c2daa00SOllivier Robert /* 10259c2daa00SOllivier Robert * Write the RSA parameters and keys as a RSA private key 10269c2daa00SOllivier Robert * encoded in PEM. 10279c2daa00SOllivier Robert */ 10282b15cb3dSCy Schubert if (strcmp(id, "sign") == 0) 10292b15cb3dSCy Schubert str = fheader("RSAsign", id, hostname); 10302b15cb3dSCy Schubert else 10312b15cb3dSCy Schubert str = fheader("RSAhost", id, hostname); 10329c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 10339c2daa00SOllivier Robert EVP_PKEY_assign_RSA(pkey, rsa); 10342b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 10352b15cb3dSCy Schubert passwd1); 10369c2daa00SOllivier Robert fclose(str); 10379c2daa00SOllivier Robert if (debug) 10382b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 10399c2daa00SOllivier Robert return (pkey); 10409c2daa00SOllivier Robert } 10419c2daa00SOllivier Robert 10429c2daa00SOllivier Robert 10439c2daa00SOllivier Robert /* 10449c2daa00SOllivier Robert * Generate DSA public/private key pair 10459c2daa00SOllivier Robert */ 10469c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 10479c2daa00SOllivier Robert gen_dsa( 10482b15cb3dSCy Schubert const char *id /* file name id */ 10499c2daa00SOllivier Robert ) 10509c2daa00SOllivier Robert { 10519c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 10529c2daa00SOllivier Robert DSA *dsa; /* DSA parameters */ 10539c2daa00SOllivier Robert FILE *str; 10549c2daa00SOllivier Robert 10559c2daa00SOllivier Robert /* 10569c2daa00SOllivier Robert * Generate DSA parameters. 10579c2daa00SOllivier Robert */ 10589c2daa00SOllivier Robert fprintf(stderr, 10599c2daa00SOllivier Robert "Generating DSA parameters (%d bits)...\n", modulus); 1060f391d6bcSXin LI dsa = genDsaParams(modulus, _UC("DSA")); 10619c2daa00SOllivier Robert fprintf(stderr, "\n"); 10629c2daa00SOllivier Robert if (dsa == NULL) { 10639c2daa00SOllivier Robert fprintf(stderr, "DSA generate parameters fails\n%s\n", 10649c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10659c2daa00SOllivier Robert return (NULL); 10669c2daa00SOllivier Robert } 10679c2daa00SOllivier Robert 10689c2daa00SOllivier Robert /* 10699c2daa00SOllivier Robert * Generate DSA keys. 10709c2daa00SOllivier Robert */ 10719c2daa00SOllivier Robert fprintf(stderr, "Generating DSA keys (%d bits)...\n", modulus); 10729c2daa00SOllivier Robert if (!DSA_generate_key(dsa)) { 10739c2daa00SOllivier Robert fprintf(stderr, "DSA generate keys fails\n%s\n", 10749c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10759c2daa00SOllivier Robert DSA_free(dsa); 10769c2daa00SOllivier Robert return (NULL); 10779c2daa00SOllivier Robert } 10789c2daa00SOllivier Robert 10799c2daa00SOllivier Robert /* 10809c2daa00SOllivier Robert * Write the DSA parameters and keys as a DSA private key 10819c2daa00SOllivier Robert * encoded in PEM. 10829c2daa00SOllivier Robert */ 10832b15cb3dSCy Schubert str = fheader("DSAsign", id, hostname); 10849c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 10859c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 10862b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 10872b15cb3dSCy Schubert passwd1); 10889c2daa00SOllivier Robert fclose(str); 10899c2daa00SOllivier Robert if (debug) 10902b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 10919c2daa00SOllivier Robert return (pkey); 10929c2daa00SOllivier Robert } 10939c2daa00SOllivier Robert 10949c2daa00SOllivier Robert 10959c2daa00SOllivier Robert /* 10962b15cb3dSCy Schubert *********************************************************************** 10972b15cb3dSCy Schubert * * 10982b15cb3dSCy Schubert * The following routines implement the Schnorr (IFF) identity scheme * 10992b15cb3dSCy Schubert * * 11002b15cb3dSCy Schubert *********************************************************************** 11019c2daa00SOllivier Robert * 11029c2daa00SOllivier Robert * The Schnorr (IFF) identity scheme is intended for use when 11039c2daa00SOllivier Robert * certificates are generated by some other trusted certificate 11042b15cb3dSCy Schubert * authority and the certificate cannot be used to convey public 11052b15cb3dSCy Schubert * parameters. There are two kinds of files: encrypted server files that 11062b15cb3dSCy Schubert * contain private and public values and nonencrypted client files that 11072b15cb3dSCy Schubert * contain only public values. New generations of server files must be 11082b15cb3dSCy Schubert * securely transmitted to all servers of the group; client files can be 11092b15cb3dSCy Schubert * distributed by any means. The scheme is self contained and 11102b15cb3dSCy Schubert * independent of new generations of host keys, sign keys and 11112b15cb3dSCy Schubert * certificates. 11129c2daa00SOllivier Robert * 11139c2daa00SOllivier Robert * The IFF values hide in a DSA cuckoo structure which uses the same 11149c2daa00SOllivier Robert * parameters. The values are used by an identity scheme based on DSA 11159c2daa00SOllivier Robert * cryptography and described in Stimson p. 285. The p is a 512-bit 11169c2daa00SOllivier Robert * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1 11179c2daa00SOllivier Robert * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a 11182b15cb3dSCy Schubert * private random group key b (0 < b < q) and public key v = g^b, then 11192b15cb3dSCy Schubert * sends (p, q, g, b) to the servers and (p, q, g, v) to the clients. 11202b15cb3dSCy Schubert * Alice challenges Bob to confirm identity using the protocol described 11212b15cb3dSCy Schubert * below. 11222b15cb3dSCy Schubert * 11232b15cb3dSCy Schubert * How it works 11242b15cb3dSCy Schubert * 11252b15cb3dSCy Schubert * The scheme goes like this. Both Alice and Bob have the public primes 11262b15cb3dSCy Schubert * p, q and generator g. The TA gives private key b to Bob and public 11272b15cb3dSCy Schubert * key v to Alice. 11282b15cb3dSCy Schubert * 11292b15cb3dSCy Schubert * Alice rolls new random challenge r (o < r < q) and sends to Bob in 11302b15cb3dSCy Schubert * the IFF request message. Bob rolls new random k (0 < k < q), then 11312b15cb3dSCy Schubert * computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x)) 11322b15cb3dSCy Schubert * to Alice in the response message. Besides making the response 11332b15cb3dSCy Schubert * shorter, the hash makes it effectivey impossible for an intruder to 11342b15cb3dSCy Schubert * solve for b by observing a number of these messages. 11352b15cb3dSCy Schubert * 11362b15cb3dSCy Schubert * Alice receives the response and computes g^y v^r mod p. After a bit 11372b15cb3dSCy Schubert * of algebra, this simplifies to g^k. If the hash of this result 11382b15cb3dSCy Schubert * matches hash(x), Alice knows that Bob has the group key b. The signed 11392b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 11402b15cb3dSCy Schubert * previously received in his certificate. 11412b15cb3dSCy Schubert */ 11422b15cb3dSCy Schubert /* 11432b15cb3dSCy Schubert * Generate Schnorr (IFF) keys. 11449c2daa00SOllivier Robert */ 11459c2daa00SOllivier Robert EVP_PKEY * /* DSA cuckoo nest */ 11462b15cb3dSCy Schubert gen_iffkey( 11472b15cb3dSCy Schubert const char *id /* file name id */ 11489c2daa00SOllivier Robert ) 11499c2daa00SOllivier Robert { 11509c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 11519c2daa00SOllivier Robert DSA *dsa; /* DSA parameters */ 11529c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 11539c2daa00SOllivier Robert BIGNUM *b, *r, *k, *u, *v, *w; /* BN temp */ 11549c2daa00SOllivier Robert FILE *str; 11559c2daa00SOllivier Robert u_int temp; 1156f391d6bcSXin LI const BIGNUM *p, *q, *g; 1157f391d6bcSXin LI BIGNUM *pub_key, *priv_key; 11589c2daa00SOllivier Robert 11599c2daa00SOllivier Robert /* 11609c2daa00SOllivier Robert * Generate DSA parameters for use as IFF parameters. 11619c2daa00SOllivier Robert */ 11622b15cb3dSCy Schubert fprintf(stderr, "Generating IFF keys (%d bits)...\n", 11632b15cb3dSCy Schubert modulus2); 1164f391d6bcSXin LI dsa = genDsaParams(modulus2, _UC("IFF")); 11659c2daa00SOllivier Robert fprintf(stderr, "\n"); 11669c2daa00SOllivier Robert if (dsa == NULL) { 11679c2daa00SOllivier Robert fprintf(stderr, "DSA generate parameters fails\n%s\n", 11689c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 1169f391d6bcSXin LI return (NULL); 11709c2daa00SOllivier Robert } 1171f391d6bcSXin LI DSA_get0_pqg(dsa, &p, &q, &g); 11729c2daa00SOllivier Robert 11739c2daa00SOllivier Robert /* 11749c2daa00SOllivier Robert * Generate the private and public keys. The DSA parameters and 11752b15cb3dSCy Schubert * private key are distributed to the servers, while all except 11762b15cb3dSCy Schubert * the private key are distributed to the clients. 11779c2daa00SOllivier Robert */ 11789c2daa00SOllivier Robert b = BN_new(); r = BN_new(); k = BN_new(); 11799c2daa00SOllivier Robert u = BN_new(); v = BN_new(); w = BN_new(); ctx = BN_CTX_new(); 1180f391d6bcSXin LI BN_rand(b, BN_num_bits(q), -1, 0); /* a */ 1181f391d6bcSXin LI BN_mod(b, b, q, ctx); 1182f391d6bcSXin LI BN_sub(v, q, b); 1183f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); /* g^(q - b) mod p */ 1184f391d6bcSXin LI BN_mod_exp(u, g, b, p, ctx); /* g^b mod p */ 1185f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 11869c2daa00SOllivier Robert temp = BN_is_one(u); 11879c2daa00SOllivier Robert fprintf(stderr, 11889c2daa00SOllivier Robert "Confirm g^(q - b) g^b = 1 mod p: %s\n", temp == 1 ? 11899c2daa00SOllivier Robert "yes" : "no"); 11909c2daa00SOllivier Robert if (!temp) { 11919c2daa00SOllivier Robert BN_free(b); BN_free(r); BN_free(k); 11929c2daa00SOllivier Robert BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 11939c2daa00SOllivier Robert return (NULL); 11949c2daa00SOllivier Robert } 1195f391d6bcSXin LI pub_key = BN_dup(v); 1196f391d6bcSXin LI priv_key = BN_dup(b); 1197f391d6bcSXin LI DSA_set0_key(dsa, pub_key, priv_key); 11989c2daa00SOllivier Robert 11999c2daa00SOllivier Robert /* 12009c2daa00SOllivier Robert * Here is a trial round of the protocol. First, Alice rolls 12012b15cb3dSCy Schubert * random nonce r mod q and sends it to Bob. She needs only 12022b15cb3dSCy Schubert * q from parameters. 12039c2daa00SOllivier Robert */ 1204f391d6bcSXin LI BN_rand(r, BN_num_bits(q), -1, 0); /* r */ 1205f391d6bcSXin LI BN_mod(r, r, q, ctx); 12069c2daa00SOllivier Robert 12079c2daa00SOllivier Robert /* 12082b15cb3dSCy Schubert * Bob rolls random nonce k mod q, computes y = k + b r mod q 12099c2daa00SOllivier Robert * and x = g^k mod p, then sends (y, x) to Alice. He needs 12102b15cb3dSCy Schubert * p, q and b from parameters and r from Alice. 12119c2daa00SOllivier Robert */ 1212f391d6bcSXin LI BN_rand(k, BN_num_bits(q), -1, 0); /* k, 0 < k < q */ 1213f391d6bcSXin LI BN_mod(k, k, q, ctx); 1214f391d6bcSXin LI BN_mod_mul(v, priv_key, r, q, ctx); /* b r mod q */ 12159c2daa00SOllivier Robert BN_add(v, v, k); 1216f391d6bcSXin LI BN_mod(v, v, q, ctx); /* y = k + b r mod q */ 1217f391d6bcSXin LI BN_mod_exp(u, g, k, p, ctx); /* x = g^k mod p */ 12189c2daa00SOllivier Robert 12199c2daa00SOllivier Robert /* 12202b15cb3dSCy Schubert * Alice verifies x = g^y v^r to confirm that Bob has group key 12212b15cb3dSCy Schubert * b. She needs p, q, g from parameters, (y, x) from Bob and the 12222b15cb3dSCy Schubert * original r. We omit the detail here thatt only the hash of y 12232b15cb3dSCy Schubert * is sent. 12249c2daa00SOllivier Robert */ 1225f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); /* g^y mod p */ 1226f391d6bcSXin LI BN_mod_exp(w, pub_key, r, p, ctx); /* v^r */ 1227f391d6bcSXin LI BN_mod_mul(v, w, v, p, ctx); /* product mod p */ 12289c2daa00SOllivier Robert temp = BN_cmp(u, v); 12299c2daa00SOllivier Robert fprintf(stderr, 12309c2daa00SOllivier Robert "Confirm g^k = g^(k + b r) g^(q - b) r: %s\n", temp == 12319c2daa00SOllivier Robert 0 ? "yes" : "no"); 12329c2daa00SOllivier Robert BN_free(b); BN_free(r); BN_free(k); 12339c2daa00SOllivier Robert BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 12349c2daa00SOllivier Robert if (temp != 0) { 12359c2daa00SOllivier Robert DSA_free(dsa); 12369c2daa00SOllivier Robert return (NULL); 12379c2daa00SOllivier Robert } 12389c2daa00SOllivier Robert 12399c2daa00SOllivier Robert /* 12402b15cb3dSCy Schubert * Write the IFF keys as an encrypted DSA private key encoded in 12412b15cb3dSCy Schubert * PEM. 12429c2daa00SOllivier Robert * 12439c2daa00SOllivier Robert * p modulus p 12449c2daa00SOllivier Robert * q modulus q 12459c2daa00SOllivier Robert * g generator g 12469c2daa00SOllivier Robert * priv_key b 12479c2daa00SOllivier Robert * public_key v 12482b15cb3dSCy Schubert * kinv not used 12492b15cb3dSCy Schubert * r not used 12509c2daa00SOllivier Robert */ 12512b15cb3dSCy Schubert str = fheader("IFFkey", id, groupname); 12529c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 12539c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 12542b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 12552b15cb3dSCy Schubert passwd1); 12569c2daa00SOllivier Robert fclose(str); 12579c2daa00SOllivier Robert if (debug) 12582b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 12599c2daa00SOllivier Robert return (pkey); 12609c2daa00SOllivier Robert } 12619c2daa00SOllivier Robert 12629c2daa00SOllivier Robert 12639c2daa00SOllivier Robert /* 12642b15cb3dSCy Schubert *********************************************************************** 12652b15cb3dSCy Schubert * * 12662b15cb3dSCy Schubert * The following routines implement the Guillou-Quisquater (GQ) * 12672b15cb3dSCy Schubert * identity scheme * 12682b15cb3dSCy Schubert * * 12692b15cb3dSCy Schubert *********************************************************************** 12709c2daa00SOllivier Robert * 12719c2daa00SOllivier Robert * The Guillou-Quisquater (GQ) identity scheme is intended for use when 12722b15cb3dSCy Schubert * the certificate can be used to convey public parameters. The scheme 12732b15cb3dSCy Schubert * uses a X509v3 certificate extension field do convey the public key of 12742b15cb3dSCy Schubert * a private key known only to servers. There are two kinds of files: 12752b15cb3dSCy Schubert * encrypted server files that contain private and public values and 12762b15cb3dSCy Schubert * nonencrypted client files that contain only public values. New 12772b15cb3dSCy Schubert * generations of server files must be securely transmitted to all 12782b15cb3dSCy Schubert * servers of the group; client files can be distributed by any means. 12792b15cb3dSCy Schubert * The scheme is self contained and independent of new generations of 12802b15cb3dSCy Schubert * host keys and sign keys. The scheme is self contained and independent 12812b15cb3dSCy Schubert * of new generations of host keys and sign keys. 12829c2daa00SOllivier Robert * 12839c2daa00SOllivier Robert * The GQ parameters hide in a RSA cuckoo structure which uses the same 12849c2daa00SOllivier Robert * parameters. The values are used by an identity scheme based on RSA 12859c2daa00SOllivier Robert * cryptography and described in Stimson p. 300 (with errors). The 512- 12869c2daa00SOllivier Robert * bit public modulus is n = p q, where p and q are secret large primes. 12879c2daa00SOllivier Robert * The TA rolls private random group key b as RSA exponent. These values 12889c2daa00SOllivier Robert * are known to all group members. 12899c2daa00SOllivier Robert * 12902b15cb3dSCy Schubert * When rolling new certificates, a server recomputes the private and 12919c2daa00SOllivier Robert * public keys. The private key u is a random roll, while the public key 12929c2daa00SOllivier Robert * is the inverse obscured by the group key v = (u^-1)^b. These values 12939c2daa00SOllivier Robert * replace the private and public keys normally generated by the RSA 12949c2daa00SOllivier Robert * scheme. Alice challenges Bob to confirm identity using the protocol 12959c2daa00SOllivier Robert * described below. 12969c2daa00SOllivier Robert * 12972b15cb3dSCy Schubert * How it works 12982b15cb3dSCy Schubert * 12992b15cb3dSCy Schubert * The scheme goes like this. Both Alice and Bob have the same modulus n 13002b15cb3dSCy Schubert * and some random b as the group key. These values are computed and 13012b15cb3dSCy Schubert * distributed in advance via secret means, although only the group key 13022b15cb3dSCy Schubert * b is truly secret. Each has a private random private key u and public 13032b15cb3dSCy Schubert * key (u^-1)^b, although not necessarily the same ones. Bob and Alice 13042b15cb3dSCy Schubert * can regenerate the key pair from time to time without affecting 13052b15cb3dSCy Schubert * operations. The public key is conveyed on the certificate in an 13062b15cb3dSCy Schubert * extension field; the private key is never revealed. 13072b15cb3dSCy Schubert * 13082b15cb3dSCy Schubert * Alice rolls new random challenge r and sends to Bob in the GQ 13092b15cb3dSCy Schubert * request message. Bob rolls new random k, then computes y = k u^r mod 13102b15cb3dSCy Schubert * n and x = k^b mod n and sends (y, hash(x)) to Alice in the response 13112b15cb3dSCy Schubert * message. Besides making the response shorter, the hash makes it 13122b15cb3dSCy Schubert * effectivey impossible for an intruder to solve for b by observing 13132b15cb3dSCy Schubert * a number of these messages. 13142b15cb3dSCy Schubert * 13152b15cb3dSCy Schubert * Alice receives the response and computes y^b v^r mod n. After a bit 13162b15cb3dSCy Schubert * of algebra, this simplifies to k^b. If the hash of this result 13172b15cb3dSCy Schubert * matches hash(x), Alice knows that Bob has the group key b. The signed 13182b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 13192b15cb3dSCy Schubert * previously received in his certificate. 13209c2daa00SOllivier Robert */ 13219c2daa00SOllivier Robert /* 13222b15cb3dSCy Schubert * Generate Guillou-Quisquater (GQ) parameters file. 13239c2daa00SOllivier Robert */ 13249c2daa00SOllivier Robert EVP_PKEY * /* RSA cuckoo nest */ 13259c2daa00SOllivier Robert gen_gqkey( 13262b15cb3dSCy Schubert const char *id /* file name id */ 13279c2daa00SOllivier Robert ) 13289c2daa00SOllivier Robert { 13299c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 13309c2daa00SOllivier Robert RSA *rsa; /* RSA parameters */ 13319c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 13329c2daa00SOllivier Robert BIGNUM *u, *v, *g, *k, *r, *y; /* BN temps */ 13339c2daa00SOllivier Robert FILE *str; 13349c2daa00SOllivier Robert u_int temp; 1335f391d6bcSXin LI BIGNUM *b; 1336f391d6bcSXin LI const BIGNUM *n; 13379c2daa00SOllivier Robert 13389c2daa00SOllivier Robert /* 13392b15cb3dSCy Schubert * Generate RSA parameters for use as GQ parameters. 13409c2daa00SOllivier Robert */ 13412b15cb3dSCy Schubert fprintf(stderr, 13422b15cb3dSCy Schubert "Generating GQ parameters (%d bits)...\n", 13432b15cb3dSCy Schubert modulus2); 1344f391d6bcSXin LI rsa = genRsaKeyPair(modulus2, _UC("GQ")); 13452b15cb3dSCy Schubert fprintf(stderr, "\n"); 13462b15cb3dSCy Schubert if (rsa == NULL) { 13472b15cb3dSCy Schubert fprintf(stderr, "RSA generate keys fails\n%s\n", 13482b15cb3dSCy Schubert ERR_error_string(ERR_get_error(), NULL)); 13492b15cb3dSCy Schubert return (NULL); 13502b15cb3dSCy Schubert } 1351f391d6bcSXin LI RSA_get0_key(rsa, &n, NULL, NULL); 13522b15cb3dSCy Schubert u = BN_new(); v = BN_new(); g = BN_new(); 13532b15cb3dSCy Schubert k = BN_new(); r = BN_new(); y = BN_new(); 1354f391d6bcSXin LI b = BN_new(); 13552b15cb3dSCy Schubert 13562b15cb3dSCy Schubert /* 13572b15cb3dSCy Schubert * Generate the group key b, which is saved in the e member of 13582b15cb3dSCy Schubert * the RSA structure. The group key is transmitted to each group 13592b15cb3dSCy Schubert * member encrypted by the member private key. 13602b15cb3dSCy Schubert */ 13612b15cb3dSCy Schubert ctx = BN_CTX_new(); 1362f391d6bcSXin LI BN_rand(b, BN_num_bits(n), -1, 0); /* b */ 1363f391d6bcSXin LI BN_mod(b, b, n, ctx); 13649c2daa00SOllivier Robert 13659c2daa00SOllivier Robert /* 13669c2daa00SOllivier Robert * When generating his certificate, Bob rolls random private key 13672b15cb3dSCy Schubert * u, then computes inverse v = u^-1. 13689c2daa00SOllivier Robert */ 1369f391d6bcSXin LI BN_rand(u, BN_num_bits(n), -1, 0); /* u */ 1370f391d6bcSXin LI BN_mod(u, u, n, ctx); 1371f391d6bcSXin LI BN_mod_inverse(v, u, n, ctx); /* u^-1 mod n */ 1372f391d6bcSXin LI BN_mod_mul(k, v, u, n, ctx); 13739c2daa00SOllivier Robert 13749c2daa00SOllivier Robert /* 13759c2daa00SOllivier Robert * Bob computes public key v = (u^-1)^b, which is saved in an 13769c2daa00SOllivier Robert * extension field on his certificate. We check that u^b v = 13779c2daa00SOllivier Robert * 1 mod n. 13789c2daa00SOllivier Robert */ 1379f391d6bcSXin LI BN_mod_exp(v, v, b, n, ctx); 1380f391d6bcSXin LI BN_mod_exp(g, u, b, n, ctx); /* u^b */ 1381f391d6bcSXin LI BN_mod_mul(g, g, v, n, ctx); /* u^b (u^-1)^b */ 13829c2daa00SOllivier Robert temp = BN_is_one(g); 13839c2daa00SOllivier Robert fprintf(stderr, 13849c2daa00SOllivier Robert "Confirm u^b (u^-1)^b = 1 mod n: %s\n", temp ? "yes" : 13859c2daa00SOllivier Robert "no"); 13869c2daa00SOllivier Robert if (!temp) { 13879c2daa00SOllivier Robert BN_free(u); BN_free(v); 13889c2daa00SOllivier Robert BN_free(g); BN_free(k); BN_free(r); BN_free(y); 13899c2daa00SOllivier Robert BN_CTX_free(ctx); 13909c2daa00SOllivier Robert RSA_free(rsa); 13919c2daa00SOllivier Robert return (NULL); 13929c2daa00SOllivier Robert } 1393f391d6bcSXin LI /* setting 'u' and 'v' into a RSA object takes over ownership. 1394f391d6bcSXin LI * Since we use these values again, we have to pass in dupes, 1395f391d6bcSXin LI * or we'll corrupt the program! 1396f391d6bcSXin LI */ 1397f391d6bcSXin LI RSA_set0_factors(rsa, BN_dup(u), BN_dup(v)); 13989c2daa00SOllivier Robert 13999c2daa00SOllivier Robert /* 14009c2daa00SOllivier Robert * Here is a trial run of the protocol. First, Alice rolls 14012b15cb3dSCy Schubert * random nonce r mod n and sends it to Bob. She needs only n 14022b15cb3dSCy Schubert * from parameters. 14039c2daa00SOllivier Robert */ 1404f391d6bcSXin LI BN_rand(r, BN_num_bits(n), -1, 0); /* r */ 1405f391d6bcSXin LI BN_mod(r, r, n, ctx); 14069c2daa00SOllivier Robert 14079c2daa00SOllivier Robert /* 14082b15cb3dSCy Schubert * Bob rolls random nonce k mod n, computes y = k u^r mod n and 14092b15cb3dSCy Schubert * g = k^b mod n, then sends (y, g) to Alice. He needs n, u, b 14102b15cb3dSCy Schubert * from parameters and r from Alice. 14119c2daa00SOllivier Robert */ 1412f391d6bcSXin LI BN_rand(k, BN_num_bits(n), -1, 0); /* k */ 1413f391d6bcSXin LI BN_mod(k, k, n, ctx); 1414f391d6bcSXin LI BN_mod_exp(y, u, r, n, ctx); /* u^r mod n */ 1415f391d6bcSXin LI BN_mod_mul(y, k, y, n, ctx); /* y = k u^r mod n */ 1416f391d6bcSXin LI BN_mod_exp(g, k, b, n, ctx); /* g = k^b mod n */ 14179c2daa00SOllivier Robert 14189c2daa00SOllivier Robert /* 14192b15cb3dSCy Schubert * Alice verifies g = v^r y^b mod n to confirm that Bob has 14202b15cb3dSCy Schubert * private key u. She needs n, g from parameters, public key v = 14212b15cb3dSCy Schubert * (u^-1)^b from the certificate, (y, g) from Bob and the 14222b15cb3dSCy Schubert * original r. We omit the detaul here that only the hash of g 14232b15cb3dSCy Schubert * is sent. 14249c2daa00SOllivier Robert */ 1425f391d6bcSXin LI BN_mod_exp(v, v, r, n, ctx); /* v^r mod n */ 1426f391d6bcSXin LI BN_mod_exp(y, y, b, n, ctx); /* y^b mod n */ 1427f391d6bcSXin LI BN_mod_mul(y, v, y, n, ctx); /* v^r y^b mod n */ 14289c2daa00SOllivier Robert temp = BN_cmp(y, g); 14299c2daa00SOllivier Robert fprintf(stderr, "Confirm g^k = v^r y^b mod n: %s\n", temp == 0 ? 14309c2daa00SOllivier Robert "yes" : "no"); 14319c2daa00SOllivier Robert BN_CTX_free(ctx); BN_free(u); BN_free(v); 14329c2daa00SOllivier Robert BN_free(g); BN_free(k); BN_free(r); BN_free(y); 14339c2daa00SOllivier Robert if (temp != 0) { 14349c2daa00SOllivier Robert RSA_free(rsa); 14359c2daa00SOllivier Robert return (NULL); 14369c2daa00SOllivier Robert } 14379c2daa00SOllivier Robert 14389c2daa00SOllivier Robert /* 14392b15cb3dSCy Schubert * Write the GQ parameter file as an encrypted RSA private key 14402b15cb3dSCy Schubert * encoded in PEM. 14419c2daa00SOllivier Robert * 14429c2daa00SOllivier Robert * n modulus n 14439c2daa00SOllivier Robert * e group key b 14442b15cb3dSCy Schubert * d not used 14459c2daa00SOllivier Robert * p private key u 14469c2daa00SOllivier Robert * q public key (u^-1)^b 14472b15cb3dSCy Schubert * dmp1 not used 14482b15cb3dSCy Schubert * dmq1 not used 14492b15cb3dSCy Schubert * iqmp not used 14509c2daa00SOllivier Robert */ 1451f391d6bcSXin LI RSA_set0_key(rsa, NULL, b, BN_dup(BN_value_one())); 1452f391d6bcSXin LI RSA_set0_crt_params(rsa, BN_dup(BN_value_one()), BN_dup(BN_value_one()), 1453f391d6bcSXin LI BN_dup(BN_value_one())); 14542b15cb3dSCy Schubert str = fheader("GQkey", id, groupname); 14559c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 14569c2daa00SOllivier Robert EVP_PKEY_assign_RSA(pkey, rsa); 14572b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 14582b15cb3dSCy Schubert passwd1); 14599c2daa00SOllivier Robert fclose(str); 14609c2daa00SOllivier Robert if (debug) 14612b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 14629c2daa00SOllivier Robert return (pkey); 14639c2daa00SOllivier Robert } 14649c2daa00SOllivier Robert 14659c2daa00SOllivier Robert 14669c2daa00SOllivier Robert /* 14672b15cb3dSCy Schubert *********************************************************************** 14682b15cb3dSCy Schubert * * 14692b15cb3dSCy Schubert * The following routines implement the Mu-Varadharajan (MV) identity * 14702b15cb3dSCy Schubert * scheme * 14712b15cb3dSCy Schubert * * 14722b15cb3dSCy Schubert *********************************************************************** 14739c2daa00SOllivier Robert * 14742b15cb3dSCy Schubert * The Mu-Varadharajan (MV) cryptosystem was originally intended when 14752b15cb3dSCy Schubert * servers broadcast messages to clients, but clients never send 14762b15cb3dSCy Schubert * messages to servers. There is one encryption key for the server and a 14772b15cb3dSCy Schubert * separate decryption key for each client. It operated something like a 14789c2daa00SOllivier Robert * pay-per-view satellite broadcasting system where the session key is 14799c2daa00SOllivier Robert * encrypted by the broadcaster and the decryption keys are held in a 14802b15cb3dSCy Schubert * tamperproof set-top box. 14819c2daa00SOllivier Robert * 14829c2daa00SOllivier Robert * The MV parameters and private encryption key hide in a DSA cuckoo 14839c2daa00SOllivier Robert * structure which uses the same parameters, but generated in a 14849c2daa00SOllivier Robert * different way. The values are used in an encryption scheme similar to 14859c2daa00SOllivier Robert * El Gamal cryptography and a polynomial formed from the expansion of 14869c2daa00SOllivier Robert * product terms (x - x[j]), as described in Mu, Y., and V. 14879c2daa00SOllivier Robert * Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001, 14889c2daa00SOllivier Robert * 223-231. The paper has significant errors and serious omissions. 14899c2daa00SOllivier Robert * 14902b15cb3dSCy Schubert * Let q be the product of n distinct primes s1[j] (j = 1...n), where 14912b15cb3dSCy Schubert * each s1[j] has m significant bits. Let p be a prime p = 2 * q + 1, so 14922b15cb3dSCy Schubert * that q and each s1[j] divide p - 1 and p has M = n * m + 1 14939c2daa00SOllivier Robert * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1) 14949c2daa00SOllivier Robert * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then 14959c2daa00SOllivier Robert * project into Zp* as exponents of g. Sometimes we have to compute an 14969c2daa00SOllivier Robert * inverse b^-1 of random b in Zq, but for that purpose we require 14979c2daa00SOllivier Robert * gcd(b, q) = 1. We expect M to be in the 500-bit range and n 14982b15cb3dSCy Schubert * relatively small, like 30. These are the parameters of the scheme and 14992b15cb3dSCy Schubert * they are expensive to compute. 15009c2daa00SOllivier Robert * 15019c2daa00SOllivier Robert * We set up an instance of the scheme as follows. A set of random 15029c2daa00SOllivier Robert * values x[j] mod q (j = 1...n), are generated as the zeros of a 15039c2daa00SOllivier Robert * polynomial of order n. The product terms (x - x[j]) are expanded to 15049c2daa00SOllivier Robert * form coefficients a[i] mod q (i = 0...n) in powers of x. These are 15059c2daa00SOllivier Robert * used as exponents of the generator g mod p to generate the private 15069c2daa00SOllivier Robert * encryption key A. The pair (gbar, ghat) of public server keys and the 15079c2daa00SOllivier Robert * pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used 15089c2daa00SOllivier Robert * to construct the decryption keys. The devil is in the details. 15099c2daa00SOllivier Robert * 15102b15cb3dSCy Schubert * This routine generates a private server encryption file including the 15112b15cb3dSCy Schubert * private encryption key E and partial decryption keys gbar and ghat. 15122b15cb3dSCy Schubert * It then generates public client decryption files including the public 15132b15cb3dSCy Schubert * keys xbar[j] and xhat[j] for each client j. The partial decryption 15142b15cb3dSCy Schubert * files are used to compute the inverse of E. These values are suitably 15152b15cb3dSCy Schubert * blinded so secrets are not revealed. 15169c2daa00SOllivier Robert * 15179c2daa00SOllivier Robert * The distinguishing characteristic of this scheme is the capability to 15189c2daa00SOllivier Robert * revoke keys. Included in the calculation of E, gbar and ghat is the 15192b15cb3dSCy Schubert * product s = prod(s1[j]) (j = 1...n) above. If the factor s1[j] is 15209c2daa00SOllivier Robert * subsequently removed from the product and E, gbar and ghat 15219c2daa00SOllivier Robert * recomputed, the jth client will no longer be able to compute E^-1 and 15222b15cb3dSCy Schubert * thus unable to decrypt the messageblock. 15232b15cb3dSCy Schubert * 15242b15cb3dSCy Schubert * How it works 15252b15cb3dSCy Schubert * 15262b15cb3dSCy Schubert * The scheme goes like this. Bob has the server values (p, E, q, 15272b15cb3dSCy Schubert * gbar, ghat) and Alice has the client values (p, xbar, xhat). 15282b15cb3dSCy Schubert * 15292b15cb3dSCy Schubert * Alice rolls new random nonce r mod p and sends to Bob in the MV 15302b15cb3dSCy Schubert * request message. Bob rolls random nonce k mod q, encrypts y = r E^k 15312b15cb3dSCy Schubert * mod p and sends (y, gbar^k, ghat^k) to Alice. 15322b15cb3dSCy Schubert * 15332b15cb3dSCy Schubert * Alice receives the response and computes the inverse (E^k)^-1 from 15342b15cb3dSCy Schubert * the partial decryption keys gbar^k, ghat^k, xbar and xhat. She then 15352b15cb3dSCy Schubert * decrypts y and verifies it matches the original r. The signed 15362b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 15372b15cb3dSCy Schubert * previously received in his certificate. 15389c2daa00SOllivier Robert */ 15399c2daa00SOllivier Robert EVP_PKEY * /* DSA cuckoo nest */ 15402b15cb3dSCy Schubert gen_mvkey( 15412b15cb3dSCy Schubert const char *id, /* file name id */ 15422b15cb3dSCy Schubert EVP_PKEY **evpars /* parameter list pointer */ 15439c2daa00SOllivier Robert ) 15449c2daa00SOllivier Robert { 15452b15cb3dSCy Schubert EVP_PKEY *pkey, *pkey1; /* private keys */ 15462b15cb3dSCy Schubert DSA *dsa, *dsa2, *sdsa; /* DSA parameters */ 15479c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 15482b15cb3dSCy Schubert BIGNUM *a[MVMAX]; /* polynomial coefficient vector */ 1549f391d6bcSXin LI BIGNUM *gs[MVMAX]; /* public key vector */ 15502b15cb3dSCy Schubert BIGNUM *s1[MVMAX]; /* private enabling keys */ 15512b15cb3dSCy Schubert BIGNUM *x[MVMAX]; /* polynomial zeros vector */ 15522b15cb3dSCy Schubert BIGNUM *xbar[MVMAX], *xhat[MVMAX]; /* private keys vector */ 15539c2daa00SOllivier Robert BIGNUM *b; /* group key */ 15549c2daa00SOllivier Robert BIGNUM *b1; /* inverse group key */ 15552b15cb3dSCy Schubert BIGNUM *s; /* enabling key */ 15569c2daa00SOllivier Robert BIGNUM *biga; /* master encryption key */ 15579c2daa00SOllivier Robert BIGNUM *bige; /* session encryption key */ 15589c2daa00SOllivier Robert BIGNUM *gbar, *ghat; /* public key */ 15599c2daa00SOllivier Robert BIGNUM *u, *v, *w; /* BN scratch */ 1560f391d6bcSXin LI BIGNUM *p, *q, *g, *priv_key, *pub_key; 15619c2daa00SOllivier Robert int i, j, n; 15629c2daa00SOllivier Robert FILE *str; 15639c2daa00SOllivier Robert u_int temp; 15649c2daa00SOllivier Robert 15659c2daa00SOllivier Robert /* 15669c2daa00SOllivier Robert * Generate MV parameters. 15679c2daa00SOllivier Robert * 15689c2daa00SOllivier Robert * The object is to generate a multiplicative group Zp* modulo a 15699c2daa00SOllivier Robert * prime p and a subset Zq mod q, where q is the product of n 15702b15cb3dSCy Schubert * distinct primes s1[j] (j = 1...n) and q divides p - 1. We 15712b15cb3dSCy Schubert * first generate n m-bit primes, where the product n m is in 15722b15cb3dSCy Schubert * the order of 512 bits. One or more of these may have to be 15732b15cb3dSCy Schubert * replaced later. As a practical matter, it is tough to find 15742b15cb3dSCy Schubert * more than 31 distinct primes for 512 bits or 61 primes for 15752b15cb3dSCy Schubert * 1024 bits. The latter can take several hundred iterations 15769c2daa00SOllivier Robert * and several minutes on a Sun Blade 1000. 15779c2daa00SOllivier Robert */ 15789c2daa00SOllivier Robert n = nkeys; 15799c2daa00SOllivier Robert fprintf(stderr, 15809c2daa00SOllivier Robert "Generating MV parameters for %d keys (%d bits)...\n", n, 15812b15cb3dSCy Schubert modulus2 / n); 15829c2daa00SOllivier Robert ctx = BN_CTX_new(); u = BN_new(); v = BN_new(); w = BN_new(); 15839c2daa00SOllivier Robert b = BN_new(); b1 = BN_new(); 15845e91a9b7SOllivier Robert dsa = DSA_new(); 1585f391d6bcSXin LI p = BN_new(); q = BN_new(); g = BN_new(); 1586f391d6bcSXin LI priv_key = BN_new(); pub_key = BN_new(); 15879c2daa00SOllivier Robert temp = 0; 15889c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 15892b15cb3dSCy Schubert s1[j] = BN_new(); 15909c2daa00SOllivier Robert while (1) { 1591f391d6bcSXin LI BN_generate_prime_ex(s1[j], modulus2 / n, 0, 15929c2daa00SOllivier Robert NULL, NULL, NULL); 15939c2daa00SOllivier Robert for (i = 1; i < j; i++) { 15949c2daa00SOllivier Robert if (BN_cmp(s1[i], s1[j]) == 0) 15959c2daa00SOllivier Robert break; 15969c2daa00SOllivier Robert } 15979c2daa00SOllivier Robert if (i == j) 15989c2daa00SOllivier Robert break; 15999c2daa00SOllivier Robert temp++; 16009c2daa00SOllivier Robert } 16019c2daa00SOllivier Robert } 16022b15cb3dSCy Schubert fprintf(stderr, "Birthday keys regenerated %d\n", temp); 16039c2daa00SOllivier Robert 16049c2daa00SOllivier Robert /* 16059c2daa00SOllivier Robert * Compute the modulus q as the product of the primes. Compute 16069c2daa00SOllivier Robert * the modulus p as 2 * q + 1 and test p for primality. If p 16079c2daa00SOllivier Robert * is composite, replace one of the primes with a new distinct 16089c2daa00SOllivier Robert * one and try again. Note that q will hardly be a secret since 16092b15cb3dSCy Schubert * we have to reveal p to servers, but not clients. However, 16109c2daa00SOllivier Robert * factoring q to find the primes should be adequately hard, as 16119c2daa00SOllivier Robert * this is the same problem considered hard in RSA. Question: is 16129c2daa00SOllivier Robert * it as hard to find n small prime factors totalling n bits as 16139c2daa00SOllivier Robert * it is to find two large prime factors totalling n bits? 16149c2daa00SOllivier Robert * Remember, the bad guy doesn't know n. 16159c2daa00SOllivier Robert */ 16169c2daa00SOllivier Robert temp = 0; 16179c2daa00SOllivier Robert while (1) { 1618f391d6bcSXin LI BN_one(q); 16199c2daa00SOllivier Robert for (j = 1; j <= n; j++) 1620f391d6bcSXin LI BN_mul(q, q, s1[j], ctx); 1621f391d6bcSXin LI BN_copy(p, q); 1622f391d6bcSXin LI BN_add(p, p, p); 1623f391d6bcSXin LI BN_add_word(p, 1); 1624f391d6bcSXin LI if (BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) 16259c2daa00SOllivier Robert break; 16269c2daa00SOllivier Robert 16272b15cb3dSCy Schubert temp++; 16289c2daa00SOllivier Robert j = temp % n + 1; 16299c2daa00SOllivier Robert while (1) { 1630f391d6bcSXin LI BN_generate_prime_ex(u, modulus2 / n, 0, 1631f391d6bcSXin LI NULL, NULL, NULL); 16329c2daa00SOllivier Robert for (i = 1; i <= n; i++) { 16339c2daa00SOllivier Robert if (BN_cmp(u, s1[i]) == 0) 16349c2daa00SOllivier Robert break; 16359c2daa00SOllivier Robert } 16369c2daa00SOllivier Robert if (i > n) 16379c2daa00SOllivier Robert break; 16389c2daa00SOllivier Robert } 16399c2daa00SOllivier Robert BN_copy(s1[j], u); 16409c2daa00SOllivier Robert } 16412b15cb3dSCy Schubert fprintf(stderr, "Defective keys regenerated %d\n", temp); 16429c2daa00SOllivier Robert 16439c2daa00SOllivier Robert /* 16449c2daa00SOllivier Robert * Compute the generator g using a random roll such that 16459c2daa00SOllivier Robert * gcd(g, p - 1) = 1 and g^q = 1. This is a generator of p, not 16462b15cb3dSCy Schubert * q. This may take several iterations. 16479c2daa00SOllivier Robert */ 1648f391d6bcSXin LI BN_copy(v, p); 16499c2daa00SOllivier Robert BN_sub_word(v, 1); 16509c2daa00SOllivier Robert while (1) { 1651f391d6bcSXin LI BN_rand(g, BN_num_bits(p) - 1, 0, 0); 1652f391d6bcSXin LI BN_mod(g, g, p, ctx); 1653f391d6bcSXin LI BN_gcd(u, g, v, ctx); 16549c2daa00SOllivier Robert if (!BN_is_one(u)) 16559c2daa00SOllivier Robert continue; 16569c2daa00SOllivier Robert 1657f391d6bcSXin LI BN_mod_exp(u, g, q, p, ctx); 16589c2daa00SOllivier Robert if (BN_is_one(u)) 16599c2daa00SOllivier Robert break; 16609c2daa00SOllivier Robert } 16619c2daa00SOllivier Robert 1662f391d6bcSXin LI DSA_set0_pqg(dsa, p, q, g); 1663f391d6bcSXin LI 16649c2daa00SOllivier Robert /* 16659c2daa00SOllivier Robert * Setup is now complete. Roll random polynomial roots x[j] 16662b15cb3dSCy Schubert * (j = 1...n) for all j. While it may not be strictly 16679c2daa00SOllivier Robert * necessary, Make sure each root has no factors in common with 16689c2daa00SOllivier Robert * q. 16699c2daa00SOllivier Robert */ 16709c2daa00SOllivier Robert fprintf(stderr, 16719c2daa00SOllivier Robert "Generating polynomial coefficients for %d roots (%d bits)\n", 1672f391d6bcSXin LI n, BN_num_bits(q)); 16739c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 16749c2daa00SOllivier Robert x[j] = BN_new(); 16752b15cb3dSCy Schubert 16769c2daa00SOllivier Robert while (1) { 1677f391d6bcSXin LI BN_rand(x[j], BN_num_bits(q), 0, 0); 1678f391d6bcSXin LI BN_mod(x[j], x[j], q, ctx); 1679f391d6bcSXin LI BN_gcd(u, x[j], q, ctx); 16809c2daa00SOllivier Robert if (BN_is_one(u)) 16819c2daa00SOllivier Robert break; 16829c2daa00SOllivier Robert } 16839c2daa00SOllivier Robert } 16849c2daa00SOllivier Robert 16859c2daa00SOllivier Robert /* 16869c2daa00SOllivier Robert * Generate polynomial coefficients a[i] (i = 0...n) from the 16879c2daa00SOllivier Robert * expansion of root products (x - x[j]) mod q for all j. The 16889c2daa00SOllivier Robert * method is a present from Charlie Boncelet. 16899c2daa00SOllivier Robert */ 16909c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 16919c2daa00SOllivier Robert a[i] = BN_new(); 16929c2daa00SOllivier Robert BN_one(a[i]); 16939c2daa00SOllivier Robert } 16949c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 16959c2daa00SOllivier Robert BN_zero(w); 16969c2daa00SOllivier Robert for (i = 0; i < j; i++) { 1697f391d6bcSXin LI BN_copy(u, q); 1698f391d6bcSXin LI BN_mod_mul(v, a[i], x[j], q, ctx); 16999c2daa00SOllivier Robert BN_sub(u, u, v); 17009c2daa00SOllivier Robert BN_add(u, u, w); 17019c2daa00SOllivier Robert BN_copy(w, a[i]); 1702f391d6bcSXin LI BN_mod(a[i], u, q, ctx); 17039c2daa00SOllivier Robert } 17049c2daa00SOllivier Robert } 17059c2daa00SOllivier Robert 17069c2daa00SOllivier Robert /* 1707f391d6bcSXin LI * Generate gs[i] = g^a[i] mod p for all i and the generator g. 17089c2daa00SOllivier Robert */ 17099c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 1710f391d6bcSXin LI gs[i] = BN_new(); 1711f391d6bcSXin LI BN_mod_exp(gs[i], g, a[i], p, ctx); 17129c2daa00SOllivier Robert } 17139c2daa00SOllivier Robert 17149c2daa00SOllivier Robert /* 1715f391d6bcSXin LI * Verify prod(gs[i]^(a[i] x[j]^i)) = 1 for all i, j. Note the 1716f391d6bcSXin LI * a[i] x[j]^i exponent is computed mod q, but the gs[i] is 17172b15cb3dSCy Schubert * computed mod p. also note the expression given in the paper 17182b15cb3dSCy Schubert * is incorrect. 17199c2daa00SOllivier Robert */ 17209c2daa00SOllivier Robert temp = 1; 17219c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17229c2daa00SOllivier Robert BN_one(u); 17239c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 17249c2daa00SOllivier Robert BN_set_word(v, i); 1725f391d6bcSXin LI BN_mod_exp(v, x[j], v, q, ctx); 1726f391d6bcSXin LI BN_mod_mul(v, v, a[i], q, ctx); 1727f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); 1728f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 17299c2daa00SOllivier Robert } 17309c2daa00SOllivier Robert if (!BN_is_one(u)) 17319c2daa00SOllivier Robert temp = 0; 17329c2daa00SOllivier Robert } 17339c2daa00SOllivier Robert fprintf(stderr, 1734f391d6bcSXin LI "Confirm prod(gs[i]^(x[j]^i)) = 1 for all i, j: %s\n", temp ? 17359c2daa00SOllivier Robert "yes" : "no"); 17369c2daa00SOllivier Robert if (!temp) { 17379c2daa00SOllivier Robert return (NULL); 17389c2daa00SOllivier Robert } 17399c2daa00SOllivier Robert 17409c2daa00SOllivier Robert /* 17419c2daa00SOllivier Robert * Make private encryption key A. Keep it around for awhile, 17429c2daa00SOllivier Robert * since it is expensive to compute. 17439c2daa00SOllivier Robert */ 17449c2daa00SOllivier Robert biga = BN_new(); 17452b15cb3dSCy Schubert 17469c2daa00SOllivier Robert BN_one(biga); 17479c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17489c2daa00SOllivier Robert for (i = 0; i < n; i++) { 17499c2daa00SOllivier Robert BN_set_word(v, i); 1750f391d6bcSXin LI BN_mod_exp(v, x[j], v, q, ctx); 1751f391d6bcSXin LI BN_mod_exp(v, gs[i], v, p, ctx); 1752f391d6bcSXin LI BN_mod_mul(biga, biga, v, p, ctx); 17539c2daa00SOllivier Robert } 17549c2daa00SOllivier Robert } 17559c2daa00SOllivier Robert 17569c2daa00SOllivier Robert /* 17579c2daa00SOllivier Robert * Roll private random group key b mod q (0 < b < q), where 17582b15cb3dSCy Schubert * gcd(b, q) = 1 to guarantee b^-1 exists, then compute b^-1 17599c2daa00SOllivier Robert * mod q. If b is changed, the client keys must be recomputed. 17609c2daa00SOllivier Robert */ 17619c2daa00SOllivier Robert while (1) { 1762f391d6bcSXin LI BN_rand(b, BN_num_bits(q), 0, 0); 1763f391d6bcSXin LI BN_mod(b, b, q, ctx); 1764f391d6bcSXin LI BN_gcd(u, b, q, ctx); 17659c2daa00SOllivier Robert if (BN_is_one(u)) 17669c2daa00SOllivier Robert break; 17679c2daa00SOllivier Robert } 1768f391d6bcSXin LI BN_mod_inverse(b1, b, q, ctx); 17699c2daa00SOllivier Robert 17709c2daa00SOllivier Robert /* 17719c2daa00SOllivier Robert * Make private client keys (xbar[j], xhat[j]) for all j. Note 17722b15cb3dSCy Schubert * that the keys for the jth client do not s1[j] or the product 17732b15cb3dSCy Schubert * s1[j]) (j = 1...n) which is q by construction. 17742b15cb3dSCy Schubert * 17752b15cb3dSCy Schubert * Compute the factor w such that w s1[j] = s1[j] for all j. The 17762b15cb3dSCy Schubert * easy way to do this is to compute (q + s1[j]) / s1[j]. 17772b15cb3dSCy Schubert * Exercise for the student: prove the remainder is always zero. 17789c2daa00SOllivier Robert */ 17799c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17809c2daa00SOllivier Robert xbar[j] = BN_new(); xhat[j] = BN_new(); 17812b15cb3dSCy Schubert 1782f391d6bcSXin LI BN_add(w, q, s1[j]); 17832b15cb3dSCy Schubert BN_div(w, u, w, s1[j], ctx); 17849c2daa00SOllivier Robert BN_zero(xbar[j]); 17859c2daa00SOllivier Robert BN_set_word(v, n); 17869c2daa00SOllivier Robert for (i = 1; i <= n; i++) { 17879c2daa00SOllivier Robert if (i == j) 17889c2daa00SOllivier Robert continue; 17892b15cb3dSCy Schubert 1790f391d6bcSXin LI BN_mod_exp(u, x[i], v, q, ctx); 17919c2daa00SOllivier Robert BN_add(xbar[j], xbar[j], u); 17929c2daa00SOllivier Robert } 1793f391d6bcSXin LI BN_mod_mul(xbar[j], xbar[j], b1, q, ctx); 1794f391d6bcSXin LI BN_mod_exp(xhat[j], x[j], v, q, ctx); 1795f391d6bcSXin LI BN_mod_mul(xhat[j], xhat[j], w, q, ctx); 17969c2daa00SOllivier Robert } 17979c2daa00SOllivier Robert 17989c2daa00SOllivier Robert /* 17992b15cb3dSCy Schubert * We revoke client j by dividing q by s1[j]. The quotient 18002b15cb3dSCy Schubert * becomes the enabling key s. Note we always have to revoke 18012b15cb3dSCy Schubert * one key; otherwise, the plaintext and cryptotext would be 18022b15cb3dSCy Schubert * identical. For the present there are no provisions to revoke 18032b15cb3dSCy Schubert * additional keys, so we sail on with only token revocations. 18049c2daa00SOllivier Robert */ 18052b15cb3dSCy Schubert s = BN_new(); 1806f391d6bcSXin LI BN_copy(s, q); 18072b15cb3dSCy Schubert BN_div(s, u, s, s1[n], ctx); 18089c2daa00SOllivier Robert 18099c2daa00SOllivier Robert /* 18102b15cb3dSCy Schubert * For each combination of clients to be revoked, make private 18112b15cb3dSCy Schubert * encryption key E = A^s and partial decryption keys gbar = g^s 18122b15cb3dSCy Schubert * and ghat = g^(s b), all mod p. The servers use these keys to 18132b15cb3dSCy Schubert * compute the session encryption key and partial decryption 18142b15cb3dSCy Schubert * keys. These values must be regenerated if the enabling key is 18152b15cb3dSCy Schubert * changed. 18169c2daa00SOllivier Robert */ 18179c2daa00SOllivier Robert bige = BN_new(); gbar = BN_new(); ghat = BN_new(); 1818f391d6bcSXin LI BN_mod_exp(bige, biga, s, p, ctx); 1819f391d6bcSXin LI BN_mod_exp(gbar, g, s, p, ctx); 1820f391d6bcSXin LI BN_mod_mul(v, s, b, q, ctx); 1821f391d6bcSXin LI BN_mod_exp(ghat, g, v, p, ctx); 18229c2daa00SOllivier Robert 18239c2daa00SOllivier Robert /* 18242b15cb3dSCy Schubert * Notes: We produce the key media in three steps. The first 18252b15cb3dSCy Schubert * step is to generate the system parameters p, q, g, b, A and 18262b15cb3dSCy Schubert * the enabling keys s1[j]. Associated with each s1[j] are 18272b15cb3dSCy Schubert * parameters xbar[j] and xhat[j]. All of these parameters are 18282b15cb3dSCy Schubert * retained in a data structure protecteted by the trusted-agent 18292b15cb3dSCy Schubert * password. The p, xbar[j] and xhat[j] paremeters are 18302b15cb3dSCy Schubert * distributed to the j clients. When the client keys are to be 18312b15cb3dSCy Schubert * activated, the enabled keys are multipied together to form 18322b15cb3dSCy Schubert * the master enabling key s. This and the other parameters are 18332b15cb3dSCy Schubert * used to compute the server encryption key E and the partial 18342b15cb3dSCy Schubert * decryption keys gbar and ghat. 18359c2daa00SOllivier Robert * 18362b15cb3dSCy Schubert * In the identity exchange the client rolls random r and sends 18372b15cb3dSCy Schubert * it to the server. The server rolls random k, which is used 18382b15cb3dSCy Schubert * only once, then computes the session key E^k and partial 18392b15cb3dSCy Schubert * decryption keys gbar^k and ghat^k. The server sends the 18402b15cb3dSCy Schubert * encrypted r along with gbar^k and ghat^k to the client. The 18412b15cb3dSCy Schubert * client completes the decryption and verifies it matches r. 18429c2daa00SOllivier Robert */ 18439c2daa00SOllivier Robert /* 18442b15cb3dSCy Schubert * Write the MV trusted-agent parameters and keys as a DSA 18452b15cb3dSCy Schubert * private key encoded in PEM. 18469c2daa00SOllivier Robert * 18479c2daa00SOllivier Robert * p modulus p 18482b15cb3dSCy Schubert * q modulus q 18492b15cb3dSCy Schubert * g generator g 18502b15cb3dSCy Schubert * priv_key A mod p 18512b15cb3dSCy Schubert * pub_key b mod q 18522b15cb3dSCy Schubert * (remaining values are not used) 18539c2daa00SOllivier Robert */ 18542b15cb3dSCy Schubert i = 0; 18552b15cb3dSCy Schubert str = fheader("MVta", "mvta", groupname); 18562b15cb3dSCy Schubert fprintf(stderr, "Generating MV trusted-authority keys\n"); 1857f391d6bcSXin LI BN_copy(priv_key, biga); 1858f391d6bcSXin LI BN_copy(pub_key, b); 1859f391d6bcSXin LI DSA_set0_key(dsa, pub_key, priv_key); 18609c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 18619c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 18622b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 18632b15cb3dSCy Schubert passwd1); 18642b15cb3dSCy Schubert evpars[i++] = pkey; 18659c2daa00SOllivier Robert if (debug) 18662b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 18679c2daa00SOllivier Robert 18689c2daa00SOllivier Robert /* 18692b15cb3dSCy Schubert * Append the MV server parameters and keys as a DSA key encoded 18702b15cb3dSCy Schubert * in PEM. 18712b15cb3dSCy Schubert * 18722b15cb3dSCy Schubert * p modulus p 18732b15cb3dSCy Schubert * q modulus q (used only when generating k) 18742b15cb3dSCy Schubert * g bige 18752b15cb3dSCy Schubert * priv_key gbar 18762b15cb3dSCy Schubert * pub_key ghat 18772b15cb3dSCy Schubert * (remaining values are not used) 18789c2daa00SOllivier Robert */ 18792b15cb3dSCy Schubert fprintf(stderr, "Generating MV server keys\n"); 18802b15cb3dSCy Schubert dsa2 = DSA_new(); 1881f391d6bcSXin LI DSA_set0_pqg(dsa2, BN_dup(p), BN_dup(q), BN_dup(bige)); 1882f391d6bcSXin LI DSA_set0_key(dsa2, BN_dup(ghat), BN_dup(gbar)); 18832b15cb3dSCy Schubert pkey1 = EVP_PKEY_new(); 18842b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey1, dsa2); 18852b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey1, cipher, NULL, 0, NULL, 18862b15cb3dSCy Schubert passwd1); 18872b15cb3dSCy Schubert evpars[i++] = pkey1; 18882b15cb3dSCy Schubert if (debug) 18892b15cb3dSCy Schubert DSA_print_fp(stderr, dsa2, 0); 18909c2daa00SOllivier Robert 18919c2daa00SOllivier Robert /* 18922b15cb3dSCy Schubert * Append the MV client parameters for each client j as DSA keys 18932b15cb3dSCy Schubert * encoded in PEM. 18949c2daa00SOllivier Robert * 18959c2daa00SOllivier Robert * p modulus p 18969c2daa00SOllivier Robert * priv_key xbar[j] mod q 18979c2daa00SOllivier Robert * pub_key xhat[j] mod q 18989c2daa00SOllivier Robert * (remaining values are not used) 18999c2daa00SOllivier Robert */ 19002b15cb3dSCy Schubert fprintf(stderr, "Generating %d MV client keys\n", n); 19012b15cb3dSCy Schubert for (j = 1; j <= n; j++) { 19022b15cb3dSCy Schubert sdsa = DSA_new(); 1903f391d6bcSXin LI DSA_set0_pqg(sdsa, BN_dup(p), BN_dup(BN_value_one()), 1904f391d6bcSXin LI BN_dup(BN_value_one())); 1905f391d6bcSXin LI DSA_set0_key(sdsa, BN_dup(xhat[j]), BN_dup(xbar[j])); 19065e91a9b7SOllivier Robert pkey1 = EVP_PKEY_new(); 19075e91a9b7SOllivier Robert EVP_PKEY_set1_DSA(pkey1, sdsa); 19082b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey1, cipher, NULL, 0, 19092b15cb3dSCy Schubert NULL, passwd1); 19102b15cb3dSCy Schubert evpars[i++] = pkey1; 19119c2daa00SOllivier Robert if (debug) 19122b15cb3dSCy Schubert DSA_print_fp(stderr, sdsa, 0); 19132b15cb3dSCy Schubert 19142b15cb3dSCy Schubert /* 1915f391d6bcSXin LI * The product (gbar^k)^xbar[j] (ghat^k)^xhat[j] and E 19162b15cb3dSCy Schubert * are inverses of each other. We check that the product 19172b15cb3dSCy Schubert * is one for each client except the ones that have been 19182b15cb3dSCy Schubert * revoked. 19192b15cb3dSCy Schubert */ 1920f391d6bcSXin LI BN_mod_exp(v, gbar, xhat[j], p, ctx); 1921f391d6bcSXin LI BN_mod_exp(u, ghat, xbar[j], p, ctx); 1922f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 1923f391d6bcSXin LI BN_mod_mul(u, u, bige, p, ctx); 19242b15cb3dSCy Schubert if (!BN_is_one(u)) { 19252b15cb3dSCy Schubert fprintf(stderr, "Revoke key %d\n", j); 19262b15cb3dSCy Schubert continue; 19279c2daa00SOllivier Robert } 19282b15cb3dSCy Schubert } 19292b15cb3dSCy Schubert evpars[i++] = NULL; 19302b15cb3dSCy Schubert fclose(str); 19319c2daa00SOllivier Robert 19329c2daa00SOllivier Robert /* 19339c2daa00SOllivier Robert * Free the countries. 19349c2daa00SOllivier Robert */ 19359c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 1936f391d6bcSXin LI BN_free(a[i]); BN_free(gs[i]); 19379c2daa00SOllivier Robert } 19382b15cb3dSCy Schubert for (j = 1; j <= n; j++) { 19392b15cb3dSCy Schubert BN_free(x[j]); BN_free(xbar[j]); BN_free(xhat[j]); 19402b15cb3dSCy Schubert BN_free(s1[j]); 19412b15cb3dSCy Schubert } 19429c2daa00SOllivier Robert return (pkey); 19439c2daa00SOllivier Robert } 19449c2daa00SOllivier Robert 19459c2daa00SOllivier Robert 19469c2daa00SOllivier Robert /* 19472b15cb3dSCy Schubert * Generate X509v3 certificate. 19489c2daa00SOllivier Robert * 19499c2daa00SOllivier Robert * The certificate consists of the version number, serial number, 19509c2daa00SOllivier Robert * validity interval, issuer name, subject name and public key. For a 19519c2daa00SOllivier Robert * self-signed certificate, the issuer name is the same as the subject 19529c2daa00SOllivier Robert * name and these items are signed using the subject private key. The 19539c2daa00SOllivier Robert * validity interval extends from the current time to the same time one 19549c2daa00SOllivier Robert * year hence. For NTP purposes, it is convenient to use the NTP seconds 19559c2daa00SOllivier Robert * of the current time as the serial number. 19569c2daa00SOllivier Robert */ 19579c2daa00SOllivier Robert int 19589c2daa00SOllivier Robert x509 ( 19592b15cb3dSCy Schubert EVP_PKEY *pkey, /* signing key */ 19602b15cb3dSCy Schubert const EVP_MD *md, /* signature/digest scheme */ 19619c2daa00SOllivier Robert char *gqpub, /* identity extension (hex string) */ 19622b15cb3dSCy Schubert const char *exten, /* private cert extension */ 19632b15cb3dSCy Schubert char *name /* subject/issuer name */ 19649c2daa00SOllivier Robert ) 19659c2daa00SOllivier Robert { 19669c2daa00SOllivier Robert X509 *cert; /* X509 certificate */ 19679c2daa00SOllivier Robert X509_NAME *subj; /* distinguished (common) name */ 19689c2daa00SOllivier Robert X509_EXTENSION *ex; /* X509v3 extension */ 19699c2daa00SOllivier Robert FILE *str; /* file handle */ 19709c2daa00SOllivier Robert ASN1_INTEGER *serial; /* serial number */ 19719c2daa00SOllivier Robert const char *id; /* digest/signature scheme name */ 19729c2daa00SOllivier Robert char pathbuf[MAXFILENAME + 1]; 19739c2daa00SOllivier Robert 19749c2daa00SOllivier Robert /* 19759c2daa00SOllivier Robert * Generate X509 self-signed certificate. 19769c2daa00SOllivier Robert * 19779c2daa00SOllivier Robert * Set the certificate serial to the NTP seconds for grins. Set 19782b15cb3dSCy Schubert * the version to 3. Set the initial validity to the current 19792b15cb3dSCy Schubert * time and the finalvalidity one year hence. 19809c2daa00SOllivier Robert */ 1981f391d6bcSXin LI id = OBJ_nid2sn(EVP_MD_pkey_type(md)); 19822b15cb3dSCy Schubert fprintf(stderr, "Generating new certificate %s %s\n", name, id); 19839c2daa00SOllivier Robert cert = X509_new(); 19849c2daa00SOllivier Robert X509_set_version(cert, 2L); 19859c2daa00SOllivier Robert serial = ASN1_INTEGER_new(); 19862b15cb3dSCy Schubert ASN1_INTEGER_set(serial, (long)epoch + JAN_1970); 19879c2daa00SOllivier Robert X509_set_serialNumber(cert, serial); 19889c2daa00SOllivier Robert ASN1_INTEGER_free(serial); 1989f0574f5cSXin LI X509_time_adj(X509_getm_notBefore(cert), 0L, &epoch); 1990f0574f5cSXin LI X509_time_adj(X509_getm_notAfter(cert), lifetime * SECSPERDAY, &epoch); 19919c2daa00SOllivier Robert subj = X509_get_subject_name(cert); 19929c2daa00SOllivier Robert X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, 19933311ff84SXin LI (u_char *)name, -1, -1, 0); 19949c2daa00SOllivier Robert subj = X509_get_issuer_name(cert); 19959c2daa00SOllivier Robert X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, 19963311ff84SXin LI (u_char *)name, -1, -1, 0); 19979c2daa00SOllivier Robert if (!X509_set_pubkey(cert, pkey)) { 19982b15cb3dSCy Schubert fprintf(stderr, "Assign certificate signing key fails\n%s\n", 19999c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20009c2daa00SOllivier Robert X509_free(cert); 20019c2daa00SOllivier Robert return (0); 20029c2daa00SOllivier Robert } 20039c2daa00SOllivier Robert 20049c2daa00SOllivier Robert /* 20059c2daa00SOllivier Robert * Add X509v3 extensions if present. These represent the minimum 20069c2daa00SOllivier Robert * set defined in RFC3280 less the certificate_policy extension, 20079c2daa00SOllivier Robert * which is seriously obfuscated in OpenSSL. 20089c2daa00SOllivier Robert */ 20099c2daa00SOllivier Robert /* 20109c2daa00SOllivier Robert * The basic_constraints extension CA:TRUE allows servers to 20119c2daa00SOllivier Robert * sign client certficitates. 20129c2daa00SOllivier Robert */ 20139c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_basic_constraints, 20149c2daa00SOllivier Robert BASIC_CONSTRAINTS); 20159c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, 20162b15cb3dSCy Schubert _UC(BASIC_CONSTRAINTS)); 20179c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20189c2daa00SOllivier Robert fprintf(stderr, "Add extension field fails\n%s\n", 20199c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20209c2daa00SOllivier Robert return (0); 20219c2daa00SOllivier Robert } 20229c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20239c2daa00SOllivier Robert 20249c2daa00SOllivier Robert /* 20259c2daa00SOllivier Robert * The key_usage extension designates the purposes the key can 20269c2daa00SOllivier Robert * be used for. 20279c2daa00SOllivier Robert */ 20289c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_key_usage, KEY_USAGE); 20292b15cb3dSCy Schubert ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, _UC(KEY_USAGE)); 20309c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20319c2daa00SOllivier Robert fprintf(stderr, "Add extension field fails\n%s\n", 20329c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20339c2daa00SOllivier Robert return (0); 20349c2daa00SOllivier Robert } 20359c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20369c2daa00SOllivier Robert /* 20379c2daa00SOllivier Robert * The subject_key_identifier is used for the GQ public key. 20389c2daa00SOllivier Robert * This should not be controversial. 20399c2daa00SOllivier Robert */ 20409c2daa00SOllivier Robert if (gqpub != NULL) { 20419c2daa00SOllivier Robert fprintf(stderr, "%s\n", LN_subject_key_identifier); 20429c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, 20439c2daa00SOllivier Robert NID_subject_key_identifier, gqpub); 20449c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20459c2daa00SOllivier Robert fprintf(stderr, 20469c2daa00SOllivier Robert "Add extension field fails\n%s\n", 20479c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20489c2daa00SOllivier Robert return (0); 20499c2daa00SOllivier Robert } 20509c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20519c2daa00SOllivier Robert } 20529c2daa00SOllivier Robert 20539c2daa00SOllivier Robert /* 20549c2daa00SOllivier Robert * The extended key usage extension is used for special purpose 20559c2daa00SOllivier Robert * here. The semantics probably do not conform to the designer's 20569c2daa00SOllivier Robert * intent and will likely change in future. 20579c2daa00SOllivier Robert * 20589c2daa00SOllivier Robert * "trustRoot" designates a root authority 20599c2daa00SOllivier Robert * "private" designates a private certificate 20609c2daa00SOllivier Robert */ 20619c2daa00SOllivier Robert if (exten != NULL) { 20629c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_ext_key_usage, exten); 20639c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, 20642b15cb3dSCy Schubert NID_ext_key_usage, _UC(exten)); 20659c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20669c2daa00SOllivier Robert fprintf(stderr, 20679c2daa00SOllivier Robert "Add extension field fails\n%s\n", 20689c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20699c2daa00SOllivier Robert return (0); 20709c2daa00SOllivier Robert } 20719c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20729c2daa00SOllivier Robert } 20739c2daa00SOllivier Robert 20749c2daa00SOllivier Robert /* 20759c2daa00SOllivier Robert * Sign and verify. 20769c2daa00SOllivier Robert */ 20779c2daa00SOllivier Robert X509_sign(cert, pkey, md); 20782b15cb3dSCy Schubert if (X509_verify(cert, pkey) <= 0) { 20799c2daa00SOllivier Robert fprintf(stderr, "Verify %s certificate fails\n%s\n", id, 20809c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20819c2daa00SOllivier Robert X509_free(cert); 20829c2daa00SOllivier Robert return (0); 20839c2daa00SOllivier Robert } 20849c2daa00SOllivier Robert 20859c2daa00SOllivier Robert /* 20869c2daa00SOllivier Robert * Write the certificate encoded in PEM. 20879c2daa00SOllivier Robert */ 20882b15cb3dSCy Schubert snprintf(pathbuf, sizeof(pathbuf), "%scert", id); 20892b15cb3dSCy Schubert str = fheader(pathbuf, "cert", hostname); 20909c2daa00SOllivier Robert PEM_write_X509(str, cert); 20919c2daa00SOllivier Robert fclose(str); 20929c2daa00SOllivier Robert if (debug) 20932b15cb3dSCy Schubert X509_print_fp(stderr, cert); 20949c2daa00SOllivier Robert X509_free(cert); 20959c2daa00SOllivier Robert return (1); 20969c2daa00SOllivier Robert } 20979c2daa00SOllivier Robert 20982b15cb3dSCy Schubert #if 0 /* asn2ntp is used only with commercial certificates */ 20999c2daa00SOllivier Robert /* 21009c2daa00SOllivier Robert * asn2ntp - convert ASN1_TIME time structure to NTP time 21019c2daa00SOllivier Robert */ 21029c2daa00SOllivier Robert u_long 21039c2daa00SOllivier Robert asn2ntp ( 21049c2daa00SOllivier Robert ASN1_TIME *asn1time /* pointer to ASN1_TIME structure */ 21059c2daa00SOllivier Robert ) 21069c2daa00SOllivier Robert { 21079c2daa00SOllivier Robert char *v; /* pointer to ASN1_TIME string */ 21089c2daa00SOllivier Robert struct tm tm; /* time decode structure time */ 21099c2daa00SOllivier Robert 21109c2daa00SOllivier Robert /* 21119c2daa00SOllivier Robert * Extract time string YYMMDDHHMMSSZ from ASN.1 time structure. 21129c2daa00SOllivier Robert * Note that the YY, MM, DD fields start with one, the HH, MM, 21139c2daa00SOllivier Robert * SS fiels start with zero and the Z character should be 'Z' 21149c2daa00SOllivier Robert * for UTC. Also note that years less than 50 map to years 21159c2daa00SOllivier Robert * greater than 100. Dontcha love ASN.1? 21169c2daa00SOllivier Robert */ 21179c2daa00SOllivier Robert if (asn1time->length > 13) 21189c2daa00SOllivier Robert return (-1); 21199c2daa00SOllivier Robert v = (char *)asn1time->data; 21209c2daa00SOllivier Robert tm.tm_year = (v[0] - '0') * 10 + v[1] - '0'; 21219c2daa00SOllivier Robert if (tm.tm_year < 50) 21229c2daa00SOllivier Robert tm.tm_year += 100; 21239c2daa00SOllivier Robert tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1; 21249c2daa00SOllivier Robert tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0'; 21259c2daa00SOllivier Robert tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0'; 21269c2daa00SOllivier Robert tm.tm_min = (v[8] - '0') * 10 + v[9] - '0'; 21279c2daa00SOllivier Robert tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0'; 21289c2daa00SOllivier Robert tm.tm_wday = 0; 21299c2daa00SOllivier Robert tm.tm_yday = 0; 21309c2daa00SOllivier Robert tm.tm_isdst = 0; 21319c2daa00SOllivier Robert return (mktime(&tm) + JAN_1970); 21329c2daa00SOllivier Robert } 21339c2daa00SOllivier Robert #endif 21349c2daa00SOllivier Robert 21359c2daa00SOllivier Robert /* 21369c2daa00SOllivier Robert * Callback routine 21379c2daa00SOllivier Robert */ 21389c2daa00SOllivier Robert void 21399c2daa00SOllivier Robert cb ( 21409c2daa00SOllivier Robert int n1, /* arg 1 */ 21419c2daa00SOllivier Robert int n2, /* arg 2 */ 21429c2daa00SOllivier Robert void *chr /* arg 3 */ 21439c2daa00SOllivier Robert ) 21449c2daa00SOllivier Robert { 21459c2daa00SOllivier Robert switch (n1) { 21469c2daa00SOllivier Robert case 0: 21479c2daa00SOllivier Robert d0++; 21489c2daa00SOllivier Robert fprintf(stderr, "%s %d %d %lu\r", (char *)chr, n1, n2, 21499c2daa00SOllivier Robert d0); 21509c2daa00SOllivier Robert break; 21519c2daa00SOllivier Robert case 1: 21529c2daa00SOllivier Robert d1++; 21539c2daa00SOllivier Robert fprintf(stderr, "%s\t\t%d %d %lu\r", (char *)chr, n1, 21549c2daa00SOllivier Robert n2, d1); 21559c2daa00SOllivier Robert break; 21569c2daa00SOllivier Robert case 2: 21579c2daa00SOllivier Robert d2++; 21589c2daa00SOllivier Robert fprintf(stderr, "%s\t\t\t\t%d %d %lu\r", (char *)chr, 21599c2daa00SOllivier Robert n1, n2, d2); 21609c2daa00SOllivier Robert break; 21619c2daa00SOllivier Robert case 3: 21629c2daa00SOllivier Robert d3++; 21639c2daa00SOllivier Robert fprintf(stderr, "%s\t\t\t\t\t\t%d %d %lu\r", 21649c2daa00SOllivier Robert (char *)chr, n1, n2, d3); 21659c2daa00SOllivier Robert break; 21669c2daa00SOllivier Robert } 21679c2daa00SOllivier Robert } 21689c2daa00SOllivier Robert 21699c2daa00SOllivier Robert 21709c2daa00SOllivier Robert /* 21719c2daa00SOllivier Robert * Generate key 21729c2daa00SOllivier Robert */ 21739c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 21749c2daa00SOllivier Robert genkey( 21752b15cb3dSCy Schubert const char *type, /* key type (RSA or DSA) */ 21762b15cb3dSCy Schubert const char *id /* file name id */ 21779c2daa00SOllivier Robert ) 21789c2daa00SOllivier Robert { 21799c2daa00SOllivier Robert if (type == NULL) 21809c2daa00SOllivier Robert return (NULL); 21819c2daa00SOllivier Robert if (strcmp(type, "RSA") == 0) 21829c2daa00SOllivier Robert return (gen_rsa(id)); 21839c2daa00SOllivier Robert 21849c2daa00SOllivier Robert else if (strcmp(type, "DSA") == 0) 21859c2daa00SOllivier Robert return (gen_dsa(id)); 21869c2daa00SOllivier Robert 21879c2daa00SOllivier Robert fprintf(stderr, "Invalid %s key type %s\n", id, type); 21889c2daa00SOllivier Robert return (NULL); 21899c2daa00SOllivier Robert } 2190f391d6bcSXin LI 2191f391d6bcSXin LI static RSA* 2192f391d6bcSXin LI genRsaKeyPair( 2193f391d6bcSXin LI int bits, 2194f391d6bcSXin LI char * what 2195f391d6bcSXin LI ) 2196f391d6bcSXin LI { 2197f391d6bcSXin LI RSA * rsa = RSA_new(); 2198f391d6bcSXin LI BN_GENCB * gcb = BN_GENCB_new(); 2199f391d6bcSXin LI BIGNUM * bne = BN_new(); 2200f391d6bcSXin LI 2201f391d6bcSXin LI if (gcb) 2202f391d6bcSXin LI BN_GENCB_set_old(gcb, cb, what); 2203f391d6bcSXin LI if (bne) 2204f391d6bcSXin LI BN_set_word(bne, 65537); 2205f391d6bcSXin LI if (!(rsa && gcb && bne && RSA_generate_key_ex( 2206f391d6bcSXin LI rsa, bits, bne, gcb))) 2207f391d6bcSXin LI { 2208f391d6bcSXin LI RSA_free(rsa); 2209f391d6bcSXin LI rsa = NULL; 2210f391d6bcSXin LI } 2211f391d6bcSXin LI BN_GENCB_free(gcb); 2212f391d6bcSXin LI BN_free(bne); 2213f391d6bcSXin LI return rsa; 2214f391d6bcSXin LI } 2215f391d6bcSXin LI 2216f391d6bcSXin LI static DSA* 2217f391d6bcSXin LI genDsaParams( 2218f391d6bcSXin LI int bits, 2219f391d6bcSXin LI char * what 2220f391d6bcSXin LI ) 2221f391d6bcSXin LI { 2222f391d6bcSXin LI 2223f391d6bcSXin LI DSA * dsa = DSA_new(); 2224f391d6bcSXin LI BN_GENCB * gcb = BN_GENCB_new(); 2225f391d6bcSXin LI u_char seed[20]; 2226f391d6bcSXin LI 2227f391d6bcSXin LI if (gcb) 2228f391d6bcSXin LI BN_GENCB_set_old(gcb, cb, what); 2229f391d6bcSXin LI RAND_bytes(seed, sizeof(seed)); 2230f391d6bcSXin LI if (!(dsa && gcb && DSA_generate_parameters_ex( 2231f391d6bcSXin LI dsa, bits, seed, sizeof(seed), NULL, NULL, gcb))) 2232f391d6bcSXin LI { 2233f391d6bcSXin LI DSA_free(dsa); 2234f391d6bcSXin LI dsa = NULL; 2235f391d6bcSXin LI } 2236f391d6bcSXin LI BN_GENCB_free(gcb); 2237f391d6bcSXin LI return dsa; 2238f391d6bcSXin LI } 2239f391d6bcSXin LI 22402b15cb3dSCy Schubert #endif /* AUTOKEY */ 22419c2daa00SOllivier Robert 22429c2daa00SOllivier Robert 22439c2daa00SOllivier Robert /* 22442b15cb3dSCy Schubert * Generate file header and link 22459c2daa00SOllivier Robert */ 22469c2daa00SOllivier Robert FILE * 22479c2daa00SOllivier Robert fheader ( 22482b15cb3dSCy Schubert const char *file, /* file name id */ 22492b15cb3dSCy Schubert const char *ulink, /* linkname */ 22502b15cb3dSCy Schubert const char *owner /* owner name */ 22519c2daa00SOllivier Robert ) 22529c2daa00SOllivier Robert { 22539c2daa00SOllivier Robert FILE *str; /* file handle */ 22542b15cb3dSCy Schubert char linkname[MAXFILENAME]; /* link name */ 22552b15cb3dSCy Schubert int temp; 2256a25439b6SCy Schubert #ifdef HAVE_UMASK 2257a25439b6SCy Schubert mode_t orig_umask; 2258a25439b6SCy Schubert #endif 22599c2daa00SOllivier Robert 22602b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_%s_%s.%u", file, 22612b15cb3dSCy Schubert owner, fstamp); 2262a25439b6SCy Schubert #ifdef HAVE_UMASK 2263a25439b6SCy Schubert orig_umask = umask( S_IWGRP | S_IRWXO ); 2264a25439b6SCy Schubert str = fopen(filename, "w"); 2265a25439b6SCy Schubert (void) umask(orig_umask); 2266a25439b6SCy Schubert #else 2267a25439b6SCy Schubert str = fopen(filename, "w"); 2268a25439b6SCy Schubert #endif 2269a25439b6SCy Schubert if (str == NULL) { 22709c2daa00SOllivier Robert perror("Write"); 22719c2daa00SOllivier Robert exit (-1); 22729c2daa00SOllivier Robert } 2273a25439b6SCy Schubert if (strcmp(ulink, "md5") == 0) { 2274a25439b6SCy Schubert strcpy(linkname,"ntp.keys"); 2275a25439b6SCy Schubert } else { 22762b15cb3dSCy Schubert snprintf(linkname, sizeof(linkname), "ntpkey_%s_%s", ulink, 22772b15cb3dSCy Schubert hostname); 2278a25439b6SCy Schubert } 22792b15cb3dSCy Schubert (void)remove(linkname); /* The symlink() line below matters */ 22809c2daa00SOllivier Robert temp = symlink(filename, linkname); 22819c2daa00SOllivier Robert if (temp < 0) 22822b15cb3dSCy Schubert perror(file); 22832b15cb3dSCy Schubert fprintf(stderr, "Generating new %s file and link\n", ulink); 22849c2daa00SOllivier Robert fprintf(stderr, "%s->%s\n", linkname, filename); 22852b15cb3dSCy Schubert fprintf(str, "# %s\n# %s\n", filename, ctime(&epoch)); 22862b15cb3dSCy Schubert return (str); 22879c2daa00SOllivier Robert } 2288