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) */ 124a466cc55SCy 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 * 269a466cc55SCy 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 { 277a466cc55SCy Schubert ssize_t len; 278a466cc55SCy Schubert char * target; 2792b15cb3dSCy Schubert 280a466cc55SCy Schubert REQUIRE(bufsiz > 0 && bufsiz <= SSIZE_MAX); 2812b15cb3dSCy Schubert 282a466cc55SCy Schubert target = emalloc(bufsiz); 283a466cc55SCy Schubert len = readlink(fname, target, bufsiz); 2842b15cb3dSCy Schubert if (len < 0) { 2852b15cb3dSCy Schubert fname[0] = '\0'; 2862b15cb3dSCy Schubert return; 2872b15cb3dSCy Schubert } 288a466cc55SCy Schubert if ((size_t)len > bufsiz - 1) 289a466cc55SCy Schubert len = bufsiz - 1; 290a466cc55SCy Schubert memcpy(fname, target, len); 2912b15cb3dSCy Schubert fname[len] = '\0'; 292a466cc55SCy 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 )) { 412*f5f40dd6SCy Schubert mvkey++; /* DLH are these two swapped? */ 4132b15cb3dSCy Schubert nkeys = OPT_VALUE_MV_PARAMS; 4142b15cb3dSCy Schubert } 4152b15cb3dSCy Schubert if (HAVE_OPT( MV_KEYS )) { 416*f5f40dd6SCy Schubert mvpar++; /* not used! */ /* DLH are these two swapped? */ 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 648*f5f40dd6SCy Schubert rsa = EVP_PKEY_get1_RSA(pkey_gqkey); 649f391d6bcSXin LI RSA_get0_factors(rsa, NULL, &q); 650f391d6bcSXin LI grpkey = BN_bn2hex(q); 651*f5f40dd6SCy Schubert RSA_free(rsa); 652f391d6bcSXin LI } 6532b15cb3dSCy Schubert 6542b15cb3dSCy Schubert /* 6552b15cb3dSCy Schubert * Write the nonencrypted GQ client parameters to the stdout 6562b15cb3dSCy Schubert * stream. The parameter file is the server key file with the 6572b15cb3dSCy Schubert * private key obscured. 6582b15cb3dSCy Schubert */ 6592b15cb3dSCy Schubert if (pkey_gqkey != NULL && HAVE_OPT(ID_KEY)) { 6602b15cb3dSCy Schubert RSA *rsa; 6612b15cb3dSCy Schubert 6622b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 6632b15cb3dSCy Schubert "ntpkey_gqpar_%s.%u", groupname, fstamp); 6642b15cb3dSCy Schubert fprintf(stderr, "Writing GQ parameters %s to stdout\n", 6652b15cb3dSCy Schubert filename); 6662b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 6672b15cb3dSCy Schubert ctime(&epoch)); 668*f5f40dd6SCy Schubert rsa = EVP_PKEY_get1_RSA(pkey_gqkey); 669f391d6bcSXin LI RSA_set0_factors(rsa, BN_dup(BN_value_one()), BN_dup(BN_value_one())); 6702b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 6712b15cb3dSCy Schubert EVP_PKEY_assign_RSA(pkey, rsa); 6722b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 6732b15cb3dSCy Schubert NULL, NULL); 6742b15cb3dSCy Schubert fflush(stdout); 675*f5f40dd6SCy Schubert if (debug) { 6762b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 6772b15cb3dSCy Schubert } 678*f5f40dd6SCy Schubert EVP_PKEY_free(pkey); 679*f5f40dd6SCy Schubert pkey = NULL; 680*f5f40dd6SCy Schubert RSA_free(rsa); 681*f5f40dd6SCy Schubert } 6822b15cb3dSCy Schubert 6832b15cb3dSCy Schubert /* 6842b15cb3dSCy Schubert * Write the encrypted GQ server keys to the stdout stream. 6852b15cb3dSCy Schubert */ 6862b15cb3dSCy Schubert if (pkey_gqkey != NULL && passwd2 != NULL) { 6872b15cb3dSCy Schubert RSA *rsa; 6882b15cb3dSCy Schubert 6892b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 6902b15cb3dSCy Schubert "ntpkey_gqkey_%s.%u", groupname, fstamp); 6912b15cb3dSCy Schubert fprintf(stderr, "Writing GQ keys %s to stdout\n", 6922b15cb3dSCy Schubert filename); 6932b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 6942b15cb3dSCy Schubert ctime(&epoch)); 695*f5f40dd6SCy Schubert rsa = EVP_PKEY_get1_RSA(pkey_gqkey); 6962b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 6972b15cb3dSCy Schubert EVP_PKEY_assign_RSA(pkey, rsa); 6982b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 6992b15cb3dSCy Schubert NULL, passwd2); 7002b15cb3dSCy Schubert fflush(stdout); 701*f5f40dd6SCy Schubert if (debug) { 7022b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 7032b15cb3dSCy Schubert } 704*f5f40dd6SCy Schubert EVP_PKEY_free(pkey); 705*f5f40dd6SCy Schubert pkey = NULL; 706*f5f40dd6SCy Schubert RSA_free(rsa); 707*f5f40dd6SCy Schubert } 7082b15cb3dSCy Schubert 7092b15cb3dSCy Schubert /* 7102b15cb3dSCy Schubert * Create new encrypted IFF server keys file if requested; 7112b15cb3dSCy Schubert * otherwise, look for existing file. 7122b15cb3dSCy Schubert */ 7132b15cb3dSCy Schubert if (iffkey) 7142b15cb3dSCy Schubert pkey_iffkey = gen_iffkey("iffkey"); 7152b15cb3dSCy Schubert if (pkey_iffkey == NULL) { 7162b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_iffkey_%s", 7172b15cb3dSCy Schubert groupname); 7182b15cb3dSCy Schubert pkey_iffkey = readkey(filename, passwd1, &fstamp, NULL); 7192b15cb3dSCy Schubert if (pkey_iffkey != NULL) { 7202b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 7212b15cb3dSCy Schubert fprintf(stderr, "Using IFF keys %s\n", 7222b15cb3dSCy Schubert filename); 7232b15cb3dSCy Schubert } 7242b15cb3dSCy Schubert } 7252b15cb3dSCy Schubert 7262b15cb3dSCy Schubert /* 7272b15cb3dSCy Schubert * Write the nonencrypted IFF client parameters to the stdout 7282b15cb3dSCy Schubert * stream. The parameter file is the server key file with the 7292b15cb3dSCy Schubert * private key obscured. 7302b15cb3dSCy Schubert */ 7312b15cb3dSCy Schubert if (pkey_iffkey != NULL && HAVE_OPT(ID_KEY)) { 7322b15cb3dSCy Schubert DSA *dsa; 7332b15cb3dSCy Schubert 7342b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7352b15cb3dSCy Schubert "ntpkey_iffpar_%s.%u", groupname, fstamp); 7362b15cb3dSCy Schubert fprintf(stderr, "Writing IFF parameters %s to stdout\n", 7372b15cb3dSCy Schubert filename); 7382b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7392b15cb3dSCy Schubert ctime(&epoch)); 740*f5f40dd6SCy Schubert dsa = EVP_PKEY_get1_DSA(pkey_iffkey); 741f391d6bcSXin LI DSA_set0_key(dsa, NULL, BN_dup(BN_value_one())); 7422b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 7432b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey, dsa); 7442b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 7452b15cb3dSCy Schubert NULL, NULL); 7462b15cb3dSCy Schubert fflush(stdout); 747*f5f40dd6SCy Schubert if (debug) { 7482b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 7492b15cb3dSCy Schubert } 750*f5f40dd6SCy Schubert EVP_PKEY_free(pkey); 751*f5f40dd6SCy Schubert pkey = NULL; 752*f5f40dd6SCy Schubert DSA_free(dsa); 753*f5f40dd6SCy Schubert } 7542b15cb3dSCy Schubert 7552b15cb3dSCy Schubert /* 7562b15cb3dSCy Schubert * Write the encrypted IFF server keys to the stdout stream. 7572b15cb3dSCy Schubert */ 7582b15cb3dSCy Schubert if (pkey_iffkey != NULL && passwd2 != NULL) { 7592b15cb3dSCy Schubert DSA *dsa; 7602b15cb3dSCy Schubert 7612b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 7622b15cb3dSCy Schubert "ntpkey_iffkey_%s.%u", groupname, fstamp); 7632b15cb3dSCy Schubert fprintf(stderr, "Writing IFF keys %s to stdout\n", 7642b15cb3dSCy Schubert filename); 7652b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 7662b15cb3dSCy Schubert ctime(&epoch)); 767*f5f40dd6SCy Schubert dsa = EVP_PKEY_get1_DSA(pkey_iffkey); 7682b15cb3dSCy Schubert pkey = EVP_PKEY_new(); 7692b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey, dsa); 7702b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 7712b15cb3dSCy Schubert NULL, passwd2); 7722b15cb3dSCy Schubert fflush(stdout); 773*f5f40dd6SCy Schubert if (debug) { 7742b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 7752b15cb3dSCy Schubert } 776*f5f40dd6SCy Schubert EVP_PKEY_free(pkey); 777*f5f40dd6SCy Schubert pkey = NULL; 778*f5f40dd6SCy Schubert DSA_free(dsa); 779*f5f40dd6SCy Schubert } 7802b15cb3dSCy Schubert 7812b15cb3dSCy Schubert /* 7822b15cb3dSCy Schubert * Create new encrypted MV trusted-authority keys file if 7832b15cb3dSCy Schubert * requested; otherwise, look for existing keys file. 7842b15cb3dSCy Schubert */ 7852b15cb3dSCy Schubert if (mvkey) 7862b15cb3dSCy Schubert pkey_mvkey = gen_mvkey("mv", pkey_mvpar); 7872b15cb3dSCy Schubert if (pkey_mvkey == NULL) { 7882b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_mvta_%s", 7892b15cb3dSCy Schubert groupname); 7902b15cb3dSCy Schubert pkey_mvkey = readkey(filename, passwd1, &fstamp, 7912b15cb3dSCy Schubert pkey_mvpar); 7922b15cb3dSCy Schubert if (pkey_mvkey != NULL) { 7932b15cb3dSCy Schubert followlink(filename, sizeof(filename)); 7942b15cb3dSCy Schubert fprintf(stderr, "Using MV keys %s\n", 7952b15cb3dSCy Schubert filename); 7962b15cb3dSCy Schubert } 7972b15cb3dSCy Schubert } 7982b15cb3dSCy Schubert 7992b15cb3dSCy Schubert /* 8002b15cb3dSCy Schubert * Write the nonencrypted MV client parameters to the stdout 8012b15cb3dSCy Schubert * stream. For the moment, we always use the client parameters 8022b15cb3dSCy Schubert * associated with client key 1. 8032b15cb3dSCy Schubert */ 8042b15cb3dSCy Schubert if (pkey_mvkey != NULL && HAVE_OPT(ID_KEY)) { 8052b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 8062b15cb3dSCy Schubert "ntpkey_mvpar_%s.%u", groupname, fstamp); 8072b15cb3dSCy Schubert fprintf(stderr, "Writing MV parameters %s to stdout\n", 8082b15cb3dSCy Schubert filename); 8092b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 8102b15cb3dSCy Schubert ctime(&epoch)); 8112b15cb3dSCy Schubert pkey = pkey_mvpar[2]; 8122b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, NULL, NULL, 0, 8132b15cb3dSCy Schubert NULL, NULL); 8142b15cb3dSCy Schubert fflush(stdout); 815*f5f40dd6SCy Schubert if (debug) { 816f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(pkey), 0); 8172b15cb3dSCy Schubert } 818*f5f40dd6SCy Schubert } 8192b15cb3dSCy Schubert 8202b15cb3dSCy Schubert /* 8212b15cb3dSCy Schubert * Write the encrypted MV server keys to the stdout stream. 8222b15cb3dSCy Schubert */ 8232b15cb3dSCy Schubert if (pkey_mvkey != NULL && passwd2 != NULL) { 8242b15cb3dSCy Schubert snprintf(filename, sizeof(filename), 8252b15cb3dSCy Schubert "ntpkey_mvkey_%s.%u", groupname, fstamp); 8262b15cb3dSCy Schubert fprintf(stderr, "Writing MV keys %s to stdout\n", 8272b15cb3dSCy Schubert filename); 8282b15cb3dSCy Schubert fprintf(stdout, "# %s\n# %s\n", filename, 8292b15cb3dSCy Schubert ctime(&epoch)); 8302b15cb3dSCy Schubert pkey = pkey_mvpar[1]; 8312b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(stdout, pkey, cipher, NULL, 0, 8322b15cb3dSCy Schubert NULL, passwd2); 8332b15cb3dSCy Schubert fflush(stdout); 834*f5f40dd6SCy Schubert if (debug) { 835f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(pkey), 0); 8362b15cb3dSCy Schubert } 837*f5f40dd6SCy Schubert } 8382b15cb3dSCy Schubert 8392b15cb3dSCy Schubert /* 8402b15cb3dSCy Schubert * Decode the digest/signature scheme and create the 8412b15cb3dSCy Schubert * certificate. Do this every time we run the program. 8422b15cb3dSCy Schubert */ 8439c2daa00SOllivier Robert ectx = EVP_get_digestbyname(scheme); 8449c2daa00SOllivier Robert if (ectx == NULL) { 8459c2daa00SOllivier Robert fprintf(stderr, 8469c2daa00SOllivier Robert "Invalid digest/signature combination %s\n", 8479c2daa00SOllivier Robert scheme); 8482b15cb3dSCy Schubert exit (-1); 8499c2daa00SOllivier Robert } 8502b15cb3dSCy Schubert x509(pkey_sign, ectx, grpkey, exten, certname); 8512b15cb3dSCy Schubert #endif /* AUTOKEY */ 8522b15cb3dSCy Schubert exit(0); 8539c2daa00SOllivier Robert } 8549c2daa00SOllivier Robert 8552b15cb3dSCy Schubert 8569c2daa00SOllivier Robert /* 8572b15cb3dSCy Schubert * Generate semi-random MD5 keys compatible with NTPv3 and NTPv4. Also, 8582b15cb3dSCy Schubert * if OpenSSL is around, generate random SHA1 keys compatible with 8592b15cb3dSCy Schubert * symmetric key cryptography. 8609c2daa00SOllivier Robert */ 8619c2daa00SOllivier Robert int 8629c2daa00SOllivier Robert gen_md5( 8632b15cb3dSCy Schubert const char *id /* file name id */ 8649c2daa00SOllivier Robert ) 8659c2daa00SOllivier Robert { 8662b15cb3dSCy Schubert u_char md5key[MD5SIZE + 1]; /* MD5 key */ 8679c2daa00SOllivier Robert FILE *str; 8689c2daa00SOllivier Robert int i, j; 8692b15cb3dSCy Schubert #ifdef OPENSSL 8702b15cb3dSCy Schubert u_char keystr[MD5SIZE]; 8712b15cb3dSCy Schubert u_char hexstr[2 * MD5SIZE + 1]; 8722b15cb3dSCy Schubert u_char hex[] = "0123456789abcdef"; 8732b15cb3dSCy Schubert #endif /* OPENSSL */ 8749c2daa00SOllivier Robert 8752b15cb3dSCy Schubert str = fheader("MD5key", id, groupname); 8769c2daa00SOllivier Robert for (i = 1; i <= MD5KEYS; i++) { 8772b15cb3dSCy Schubert for (j = 0; j < MD5SIZE; j++) { 878a25439b6SCy Schubert u_char temp; 8792b15cb3dSCy Schubert 8809c2daa00SOllivier Robert while (1) { 8812b15cb3dSCy Schubert int rc; 8822b15cb3dSCy Schubert 883a25439b6SCy Schubert rc = ntp_crypto_random_buf( 884a25439b6SCy Schubert &temp, sizeof(temp)); 8852b15cb3dSCy Schubert if (-1 == rc) { 8862b15cb3dSCy Schubert fprintf(stderr, "ntp_crypto_random_buf() failed.\n"); 8872b15cb3dSCy Schubert exit (-1); 8882b15cb3dSCy Schubert } 8899c2daa00SOllivier Robert if (temp == '#') 8909c2daa00SOllivier Robert continue; 8912b15cb3dSCy Schubert 8929c2daa00SOllivier Robert if (temp > 0x20 && temp < 0x7f) 8939c2daa00SOllivier Robert break; 8949c2daa00SOllivier Robert } 895a25439b6SCy Schubert md5key[j] = temp; 8969c2daa00SOllivier Robert } 8972b15cb3dSCy Schubert md5key[j] = '\0'; 8982b15cb3dSCy Schubert fprintf(str, "%2d MD5 %s # MD5 key\n", i, 8999c2daa00SOllivier Robert md5key); 9009c2daa00SOllivier Robert } 9012b15cb3dSCy Schubert #ifdef OPENSSL 9022b15cb3dSCy Schubert for (i = 1; i <= MD5KEYS; i++) { 9032b15cb3dSCy Schubert RAND_bytes(keystr, 20); 9042b15cb3dSCy Schubert for (j = 0; j < MD5SIZE; j++) { 9052b15cb3dSCy Schubert hexstr[2 * j] = hex[keystr[j] >> 4]; 9062b15cb3dSCy Schubert hexstr[2 * j + 1] = hex[keystr[j] & 0xf]; 9072b15cb3dSCy Schubert } 9082b15cb3dSCy Schubert hexstr[2 * MD5SIZE] = '\0'; 9092b15cb3dSCy Schubert fprintf(str, "%2d SHA1 %s # SHA1 key\n", i + MD5KEYS, 9102b15cb3dSCy Schubert hexstr); 9119c2daa00SOllivier Robert } 9129c2daa00SOllivier Robert #endif /* OPENSSL */ 9132b15cb3dSCy Schubert fclose(str); 9142b15cb3dSCy Schubert return (1); 9152b15cb3dSCy Schubert } 9169c2daa00SOllivier Robert 9179c2daa00SOllivier Robert 9182b15cb3dSCy Schubert #ifdef AUTOKEY 9192b15cb3dSCy Schubert /* 9202b15cb3dSCy Schubert * readkey - load cryptographic parameters and keys 9212b15cb3dSCy Schubert * 9222b15cb3dSCy Schubert * This routine loads a PEM-encoded file of given name and password and 9232b15cb3dSCy Schubert * extracts the filestamp from the file name. It returns a pointer to 9242b15cb3dSCy Schubert * the first key if valid, NULL if not. 9252b15cb3dSCy Schubert */ 9262b15cb3dSCy Schubert EVP_PKEY * /* public/private key pair */ 9272b15cb3dSCy Schubert readkey( 9282b15cb3dSCy Schubert char *cp, /* file name */ 9292b15cb3dSCy Schubert char *passwd, /* password */ 9302b15cb3dSCy Schubert u_int *estamp, /* file stamp */ 9312b15cb3dSCy Schubert EVP_PKEY **evpars /* parameter list pointer */ 9322b15cb3dSCy Schubert ) 9332b15cb3dSCy Schubert { 9342b15cb3dSCy Schubert FILE *str; /* file handle */ 9352b15cb3dSCy Schubert EVP_PKEY *pkey = NULL; /* public/private key */ 9362b15cb3dSCy Schubert u_int gstamp; /* filestamp */ 9372b15cb3dSCy Schubert char linkname[MAXFILENAME]; /* filestamp buffer) */ 9382b15cb3dSCy Schubert EVP_PKEY *parkey; 9392b15cb3dSCy Schubert char *ptr; 9402b15cb3dSCy Schubert int i; 9412b15cb3dSCy Schubert 9422b15cb3dSCy Schubert /* 9432b15cb3dSCy Schubert * Open the key file. 9442b15cb3dSCy Schubert */ 9452b15cb3dSCy Schubert str = fopen(cp, "r"); 9462b15cb3dSCy Schubert if (str == NULL) 9472b15cb3dSCy Schubert return (NULL); 9482b15cb3dSCy Schubert 9492b15cb3dSCy Schubert /* 9502b15cb3dSCy Schubert * Read the filestamp, which is contained in the first line. 9512b15cb3dSCy Schubert */ 9522b15cb3dSCy Schubert if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) { 9532b15cb3dSCy Schubert fprintf(stderr, "Empty key file %s\n", cp); 9542b15cb3dSCy Schubert fclose(str); 9552b15cb3dSCy Schubert return (NULL); 9562b15cb3dSCy Schubert } 9572b15cb3dSCy Schubert if ((ptr = strrchr(ptr, '.')) == NULL) { 9582b15cb3dSCy Schubert fprintf(stderr, "No filestamp found in %s\n", cp); 9592b15cb3dSCy Schubert fclose(str); 9602b15cb3dSCy Schubert return (NULL); 9612b15cb3dSCy Schubert } 9622b15cb3dSCy Schubert if (sscanf(++ptr, "%u", &gstamp) != 1) { 9632b15cb3dSCy Schubert fprintf(stderr, "Invalid filestamp found in %s\n", cp); 9642b15cb3dSCy Schubert fclose(str); 9652b15cb3dSCy Schubert return (NULL); 9662b15cb3dSCy Schubert } 9672b15cb3dSCy Schubert 9682b15cb3dSCy Schubert /* 9692b15cb3dSCy Schubert * Read and decrypt PEM-encoded private keys. The first one 9702b15cb3dSCy Schubert * found is returned. If others are expected, add them to the 9712b15cb3dSCy Schubert * parameter list. 9722b15cb3dSCy Schubert */ 9732b15cb3dSCy Schubert for (i = 0; i <= MVMAX - 1;) { 9742b15cb3dSCy Schubert parkey = PEM_read_PrivateKey(str, NULL, NULL, passwd); 9752b15cb3dSCy Schubert if (evpars != NULL) { 9762b15cb3dSCy Schubert evpars[i++] = parkey; 9772b15cb3dSCy Schubert evpars[i] = NULL; 9782b15cb3dSCy Schubert } 9792b15cb3dSCy Schubert if (parkey == NULL) 9802b15cb3dSCy Schubert break; 9812b15cb3dSCy Schubert 9822b15cb3dSCy Schubert if (pkey == NULL) 9832b15cb3dSCy Schubert pkey = parkey; 9842b15cb3dSCy Schubert if (debug) { 985f391d6bcSXin LI if (EVP_PKEY_base_id(parkey) == EVP_PKEY_DSA) 986f391d6bcSXin LI DSA_print_fp(stderr, EVP_PKEY_get0_DSA(parkey), 9872b15cb3dSCy Schubert 0); 988f391d6bcSXin LI else if (EVP_PKEY_base_id(parkey) == EVP_PKEY_RSA) 989f391d6bcSXin LI RSA_print_fp(stderr, EVP_PKEY_get0_RSA(parkey), 9902b15cb3dSCy Schubert 0); 9912b15cb3dSCy Schubert } 9922b15cb3dSCy Schubert } 9932b15cb3dSCy Schubert fclose(str); 9942b15cb3dSCy Schubert if (pkey == NULL) { 9952b15cb3dSCy Schubert fprintf(stderr, "Corrupt file %s or wrong key %s\n%s\n", 9962b15cb3dSCy Schubert cp, passwd, ERR_error_string(ERR_get_error(), 9972b15cb3dSCy Schubert NULL)); 9982b15cb3dSCy Schubert exit (-1); 9992b15cb3dSCy Schubert } 10002b15cb3dSCy Schubert *estamp = gstamp; 10012b15cb3dSCy Schubert return (pkey); 10022b15cb3dSCy Schubert } 10032b15cb3dSCy Schubert 10042b15cb3dSCy Schubert 10059c2daa00SOllivier Robert /* 10069c2daa00SOllivier Robert * Generate RSA public/private key pair 10079c2daa00SOllivier Robert */ 10089c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 10099c2daa00SOllivier Robert gen_rsa( 10102b15cb3dSCy Schubert const char *id /* file name id */ 10119c2daa00SOllivier Robert ) 10129c2daa00SOllivier Robert { 10139c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 10149c2daa00SOllivier Robert RSA *rsa; /* RSA parameters and key pair */ 10159c2daa00SOllivier Robert FILE *str; 10169c2daa00SOllivier Robert 10179c2daa00SOllivier Robert fprintf(stderr, "Generating RSA keys (%d bits)...\n", modulus); 1018f391d6bcSXin LI rsa = genRsaKeyPair(modulus, _UC("RSA")); 10199c2daa00SOllivier Robert fprintf(stderr, "\n"); 10209c2daa00SOllivier Robert if (rsa == NULL) { 10219c2daa00SOllivier Robert fprintf(stderr, "RSA generate keys fails\n%s\n", 10229c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10239c2daa00SOllivier Robert return (NULL); 10249c2daa00SOllivier Robert } 10259c2daa00SOllivier Robert 10269c2daa00SOllivier Robert /* 10279c2daa00SOllivier Robert * For signature encryption it is not necessary that the RSA 10289c2daa00SOllivier Robert * parameters be strictly groomed and once in a while the 10299c2daa00SOllivier Robert * modulus turns out to be non-prime. Just for grins, we check 10309c2daa00SOllivier Robert * the primality. 10319c2daa00SOllivier Robert */ 10329c2daa00SOllivier Robert if (!RSA_check_key(rsa)) { 10339c2daa00SOllivier Robert fprintf(stderr, "Invalid RSA key\n%s\n", 10349c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10359c2daa00SOllivier Robert RSA_free(rsa); 10369c2daa00SOllivier Robert return (NULL); 10379c2daa00SOllivier Robert } 10389c2daa00SOllivier Robert 10399c2daa00SOllivier Robert /* 10409c2daa00SOllivier Robert * Write the RSA parameters and keys as a RSA private key 10419c2daa00SOllivier Robert * encoded in PEM. 10429c2daa00SOllivier Robert */ 10432b15cb3dSCy Schubert if (strcmp(id, "sign") == 0) 10442b15cb3dSCy Schubert str = fheader("RSAsign", id, hostname); 10452b15cb3dSCy Schubert else 10462b15cb3dSCy Schubert str = fheader("RSAhost", id, hostname); 10479c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 10489c2daa00SOllivier Robert EVP_PKEY_assign_RSA(pkey, rsa); 10492b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 10502b15cb3dSCy Schubert passwd1); 10519c2daa00SOllivier Robert fclose(str); 10529c2daa00SOllivier Robert if (debug) 10532b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 10549c2daa00SOllivier Robert return (pkey); 10559c2daa00SOllivier Robert } 10569c2daa00SOllivier Robert 10579c2daa00SOllivier Robert 10589c2daa00SOllivier Robert /* 10599c2daa00SOllivier Robert * Generate DSA public/private key pair 10609c2daa00SOllivier Robert */ 10619c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 10629c2daa00SOllivier Robert gen_dsa( 10632b15cb3dSCy Schubert const char *id /* file name id */ 10649c2daa00SOllivier Robert ) 10659c2daa00SOllivier Robert { 10669c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 10679c2daa00SOllivier Robert DSA *dsa; /* DSA parameters */ 10689c2daa00SOllivier Robert FILE *str; 10699c2daa00SOllivier Robert 10709c2daa00SOllivier Robert /* 10719c2daa00SOllivier Robert * Generate DSA parameters. 10729c2daa00SOllivier Robert */ 10739c2daa00SOllivier Robert fprintf(stderr, 10749c2daa00SOllivier Robert "Generating DSA parameters (%d bits)...\n", modulus); 1075f391d6bcSXin LI dsa = genDsaParams(modulus, _UC("DSA")); 10769c2daa00SOllivier Robert fprintf(stderr, "\n"); 10779c2daa00SOllivier Robert if (dsa == NULL) { 10789c2daa00SOllivier Robert fprintf(stderr, "DSA generate parameters fails\n%s\n", 10799c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10809c2daa00SOllivier Robert return (NULL); 10819c2daa00SOllivier Robert } 10829c2daa00SOllivier Robert 10839c2daa00SOllivier Robert /* 10849c2daa00SOllivier Robert * Generate DSA keys. 10859c2daa00SOllivier Robert */ 10869c2daa00SOllivier Robert fprintf(stderr, "Generating DSA keys (%d bits)...\n", modulus); 10879c2daa00SOllivier Robert if (!DSA_generate_key(dsa)) { 10889c2daa00SOllivier Robert fprintf(stderr, "DSA generate keys fails\n%s\n", 10899c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 10909c2daa00SOllivier Robert DSA_free(dsa); 10919c2daa00SOllivier Robert return (NULL); 10929c2daa00SOllivier Robert } 10939c2daa00SOllivier Robert 10949c2daa00SOllivier Robert /* 10959c2daa00SOllivier Robert * Write the DSA parameters and keys as a DSA private key 10969c2daa00SOllivier Robert * encoded in PEM. 10979c2daa00SOllivier Robert */ 10982b15cb3dSCy Schubert str = fheader("DSAsign", id, hostname); 10999c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 11009c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 11012b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 11022b15cb3dSCy Schubert passwd1); 11039c2daa00SOllivier Robert fclose(str); 11049c2daa00SOllivier Robert if (debug) 11052b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 11069c2daa00SOllivier Robert return (pkey); 11079c2daa00SOllivier Robert } 11089c2daa00SOllivier Robert 11099c2daa00SOllivier Robert 11109c2daa00SOllivier Robert /* 11112b15cb3dSCy Schubert *********************************************************************** 11122b15cb3dSCy Schubert * * 11132b15cb3dSCy Schubert * The following routines implement the Schnorr (IFF) identity scheme * 11142b15cb3dSCy Schubert * * 11152b15cb3dSCy Schubert *********************************************************************** 11169c2daa00SOllivier Robert * 11179c2daa00SOllivier Robert * The Schnorr (IFF) identity scheme is intended for use when 11189c2daa00SOllivier Robert * certificates are generated by some other trusted certificate 11192b15cb3dSCy Schubert * authority and the certificate cannot be used to convey public 11202b15cb3dSCy Schubert * parameters. There are two kinds of files: encrypted server files that 11212b15cb3dSCy Schubert * contain private and public values and nonencrypted client files that 11222b15cb3dSCy Schubert * contain only public values. New generations of server files must be 11232b15cb3dSCy Schubert * securely transmitted to all servers of the group; client files can be 11242b15cb3dSCy Schubert * distributed by any means. The scheme is self contained and 11252b15cb3dSCy Schubert * independent of new generations of host keys, sign keys and 11262b15cb3dSCy Schubert * certificates. 11279c2daa00SOllivier Robert * 11289c2daa00SOllivier Robert * The IFF values hide in a DSA cuckoo structure which uses the same 11299c2daa00SOllivier Robert * parameters. The values are used by an identity scheme based on DSA 11309c2daa00SOllivier Robert * cryptography and described in Stimson p. 285. The p is a 512-bit 11319c2daa00SOllivier Robert * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1 11329c2daa00SOllivier Robert * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a 11332b15cb3dSCy Schubert * private random group key b (0 < b < q) and public key v = g^b, then 11342b15cb3dSCy Schubert * sends (p, q, g, b) to the servers and (p, q, g, v) to the clients. 11352b15cb3dSCy Schubert * Alice challenges Bob to confirm identity using the protocol described 11362b15cb3dSCy Schubert * below. 11372b15cb3dSCy Schubert * 11382b15cb3dSCy Schubert * How it works 11392b15cb3dSCy Schubert * 11402b15cb3dSCy Schubert * The scheme goes like this. Both Alice and Bob have the public primes 11412b15cb3dSCy Schubert * p, q and generator g. The TA gives private key b to Bob and public 11422b15cb3dSCy Schubert * key v to Alice. 11432b15cb3dSCy Schubert * 11442b15cb3dSCy Schubert * Alice rolls new random challenge r (o < r < q) and sends to Bob in 11452b15cb3dSCy Schubert * the IFF request message. Bob rolls new random k (0 < k < q), then 11462b15cb3dSCy Schubert * computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x)) 11472b15cb3dSCy Schubert * to Alice in the response message. Besides making the response 11482b15cb3dSCy Schubert * shorter, the hash makes it effectivey impossible for an intruder to 11492b15cb3dSCy Schubert * solve for b by observing a number of these messages. 11502b15cb3dSCy Schubert * 11512b15cb3dSCy Schubert * Alice receives the response and computes g^y v^r mod p. After a bit 11522b15cb3dSCy Schubert * of algebra, this simplifies to g^k. If the hash of this result 11532b15cb3dSCy Schubert * matches hash(x), Alice knows that Bob has the group key b. The signed 11542b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 11552b15cb3dSCy Schubert * previously received in his certificate. 11562b15cb3dSCy Schubert */ 11572b15cb3dSCy Schubert /* 11582b15cb3dSCy Schubert * Generate Schnorr (IFF) keys. 11599c2daa00SOllivier Robert */ 11609c2daa00SOllivier Robert EVP_PKEY * /* DSA cuckoo nest */ 11612b15cb3dSCy Schubert gen_iffkey( 11622b15cb3dSCy Schubert const char *id /* file name id */ 11639c2daa00SOllivier Robert ) 11649c2daa00SOllivier Robert { 11659c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 11669c2daa00SOllivier Robert DSA *dsa; /* DSA parameters */ 11679c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 11689c2daa00SOllivier Robert BIGNUM *b, *r, *k, *u, *v, *w; /* BN temp */ 11699c2daa00SOllivier Robert FILE *str; 11709c2daa00SOllivier Robert u_int temp; 1171f391d6bcSXin LI const BIGNUM *p, *q, *g; 1172f391d6bcSXin LI BIGNUM *pub_key, *priv_key; 11739c2daa00SOllivier Robert 11749c2daa00SOllivier Robert /* 11759c2daa00SOllivier Robert * Generate DSA parameters for use as IFF parameters. 11769c2daa00SOllivier Robert */ 11772b15cb3dSCy Schubert fprintf(stderr, "Generating IFF keys (%d bits)...\n", 11782b15cb3dSCy Schubert modulus2); 1179f391d6bcSXin LI dsa = genDsaParams(modulus2, _UC("IFF")); 11809c2daa00SOllivier Robert fprintf(stderr, "\n"); 11819c2daa00SOllivier Robert if (dsa == NULL) { 11829c2daa00SOllivier Robert fprintf(stderr, "DSA generate parameters fails\n%s\n", 11839c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 1184f391d6bcSXin LI return (NULL); 11859c2daa00SOllivier Robert } 1186f391d6bcSXin LI DSA_get0_pqg(dsa, &p, &q, &g); 11879c2daa00SOllivier Robert 11889c2daa00SOllivier Robert /* 11899c2daa00SOllivier Robert * Generate the private and public keys. The DSA parameters and 11902b15cb3dSCy Schubert * private key are distributed to the servers, while all except 11912b15cb3dSCy Schubert * the private key are distributed to the clients. 11929c2daa00SOllivier Robert */ 11939c2daa00SOllivier Robert b = BN_new(); r = BN_new(); k = BN_new(); 11949c2daa00SOllivier Robert u = BN_new(); v = BN_new(); w = BN_new(); ctx = BN_CTX_new(); 1195f391d6bcSXin LI BN_rand(b, BN_num_bits(q), -1, 0); /* a */ 1196f391d6bcSXin LI BN_mod(b, b, q, ctx); 1197f391d6bcSXin LI BN_sub(v, q, b); 1198f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); /* g^(q - b) mod p */ 1199f391d6bcSXin LI BN_mod_exp(u, g, b, p, ctx); /* g^b mod p */ 1200f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 12019c2daa00SOllivier Robert temp = BN_is_one(u); 12029c2daa00SOllivier Robert fprintf(stderr, 12039c2daa00SOllivier Robert "Confirm g^(q - b) g^b = 1 mod p: %s\n", temp == 1 ? 12049c2daa00SOllivier Robert "yes" : "no"); 12059c2daa00SOllivier Robert if (!temp) { 12069c2daa00SOllivier Robert BN_free(b); BN_free(r); BN_free(k); 12079c2daa00SOllivier Robert BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 12089c2daa00SOllivier Robert return (NULL); 12099c2daa00SOllivier Robert } 1210f391d6bcSXin LI pub_key = BN_dup(v); 1211f391d6bcSXin LI priv_key = BN_dup(b); 1212f391d6bcSXin LI DSA_set0_key(dsa, pub_key, priv_key); 12139c2daa00SOllivier Robert 12149c2daa00SOllivier Robert /* 12159c2daa00SOllivier Robert * Here is a trial round of the protocol. First, Alice rolls 12162b15cb3dSCy Schubert * random nonce r mod q and sends it to Bob. She needs only 12172b15cb3dSCy Schubert * q from parameters. 12189c2daa00SOllivier Robert */ 1219f391d6bcSXin LI BN_rand(r, BN_num_bits(q), -1, 0); /* r */ 1220f391d6bcSXin LI BN_mod(r, r, q, ctx); 12219c2daa00SOllivier Robert 12229c2daa00SOllivier Robert /* 12232b15cb3dSCy Schubert * Bob rolls random nonce k mod q, computes y = k + b r mod q 12249c2daa00SOllivier Robert * and x = g^k mod p, then sends (y, x) to Alice. He needs 12252b15cb3dSCy Schubert * p, q and b from parameters and r from Alice. 12269c2daa00SOllivier Robert */ 1227f391d6bcSXin LI BN_rand(k, BN_num_bits(q), -1, 0); /* k, 0 < k < q */ 1228f391d6bcSXin LI BN_mod(k, k, q, ctx); 1229f391d6bcSXin LI BN_mod_mul(v, priv_key, r, q, ctx); /* b r mod q */ 12309c2daa00SOllivier Robert BN_add(v, v, k); 1231f391d6bcSXin LI BN_mod(v, v, q, ctx); /* y = k + b r mod q */ 1232f391d6bcSXin LI BN_mod_exp(u, g, k, p, ctx); /* x = g^k mod p */ 12339c2daa00SOllivier Robert 12349c2daa00SOllivier Robert /* 12352b15cb3dSCy Schubert * Alice verifies x = g^y v^r to confirm that Bob has group key 12362b15cb3dSCy Schubert * b. She needs p, q, g from parameters, (y, x) from Bob and the 12372b15cb3dSCy Schubert * original r. We omit the detail here thatt only the hash of y 12382b15cb3dSCy Schubert * is sent. 12399c2daa00SOllivier Robert */ 1240f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); /* g^y mod p */ 1241f391d6bcSXin LI BN_mod_exp(w, pub_key, r, p, ctx); /* v^r */ 1242f391d6bcSXin LI BN_mod_mul(v, w, v, p, ctx); /* product mod p */ 12439c2daa00SOllivier Robert temp = BN_cmp(u, v); 12449c2daa00SOllivier Robert fprintf(stderr, 12459c2daa00SOllivier Robert "Confirm g^k = g^(k + b r) g^(q - b) r: %s\n", temp == 12469c2daa00SOllivier Robert 0 ? "yes" : "no"); 12479c2daa00SOllivier Robert BN_free(b); BN_free(r); BN_free(k); 12489c2daa00SOllivier Robert BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 12499c2daa00SOllivier Robert if (temp != 0) { 12509c2daa00SOllivier Robert DSA_free(dsa); 12519c2daa00SOllivier Robert return (NULL); 12529c2daa00SOllivier Robert } 12539c2daa00SOllivier Robert 12549c2daa00SOllivier Robert /* 12552b15cb3dSCy Schubert * Write the IFF keys as an encrypted DSA private key encoded in 12562b15cb3dSCy Schubert * PEM. 12579c2daa00SOllivier Robert * 12589c2daa00SOllivier Robert * p modulus p 12599c2daa00SOllivier Robert * q modulus q 12609c2daa00SOllivier Robert * g generator g 12619c2daa00SOllivier Robert * priv_key b 12629c2daa00SOllivier Robert * public_key v 12632b15cb3dSCy Schubert * kinv not used 12642b15cb3dSCy Schubert * r not used 12659c2daa00SOllivier Robert */ 12662b15cb3dSCy Schubert str = fheader("IFFkey", id, groupname); 12679c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 12689c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 12692b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 12702b15cb3dSCy Schubert passwd1); 12719c2daa00SOllivier Robert fclose(str); 12729c2daa00SOllivier Robert if (debug) 12732b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 12749c2daa00SOllivier Robert return (pkey); 12759c2daa00SOllivier Robert } 12769c2daa00SOllivier Robert 12779c2daa00SOllivier Robert 12789c2daa00SOllivier Robert /* 12792b15cb3dSCy Schubert *********************************************************************** 12802b15cb3dSCy Schubert * * 12812b15cb3dSCy Schubert * The following routines implement the Guillou-Quisquater (GQ) * 12822b15cb3dSCy Schubert * identity scheme * 12832b15cb3dSCy Schubert * * 12842b15cb3dSCy Schubert *********************************************************************** 12859c2daa00SOllivier Robert * 12869c2daa00SOllivier Robert * The Guillou-Quisquater (GQ) identity scheme is intended for use when 12872b15cb3dSCy Schubert * the certificate can be used to convey public parameters. The scheme 12882b15cb3dSCy Schubert * uses a X509v3 certificate extension field do convey the public key of 12892b15cb3dSCy Schubert * a private key known only to servers. There are two kinds of files: 12902b15cb3dSCy Schubert * encrypted server files that contain private and public values and 12912b15cb3dSCy Schubert * nonencrypted client files that contain only public values. New 12922b15cb3dSCy Schubert * generations of server files must be securely transmitted to all 12932b15cb3dSCy Schubert * servers of the group; client files can be distributed by any means. 12942b15cb3dSCy Schubert * The scheme is self contained and independent of new generations of 12952b15cb3dSCy Schubert * host keys and sign keys. The scheme is self contained and independent 12962b15cb3dSCy Schubert * of new generations of host keys and sign keys. 12979c2daa00SOllivier Robert * 12989c2daa00SOllivier Robert * The GQ parameters hide in a RSA cuckoo structure which uses the same 12999c2daa00SOllivier Robert * parameters. The values are used by an identity scheme based on RSA 13009c2daa00SOllivier Robert * cryptography and described in Stimson p. 300 (with errors). The 512- 13019c2daa00SOllivier Robert * bit public modulus is n = p q, where p and q are secret large primes. 13029c2daa00SOllivier Robert * The TA rolls private random group key b as RSA exponent. These values 13039c2daa00SOllivier Robert * are known to all group members. 13049c2daa00SOllivier Robert * 13052b15cb3dSCy Schubert * When rolling new certificates, a server recomputes the private and 13069c2daa00SOllivier Robert * public keys. The private key u is a random roll, while the public key 13079c2daa00SOllivier Robert * is the inverse obscured by the group key v = (u^-1)^b. These values 13089c2daa00SOllivier Robert * replace the private and public keys normally generated by the RSA 13099c2daa00SOllivier Robert * scheme. Alice challenges Bob to confirm identity using the protocol 13109c2daa00SOllivier Robert * described below. 13119c2daa00SOllivier Robert * 13122b15cb3dSCy Schubert * How it works 13132b15cb3dSCy Schubert * 13142b15cb3dSCy Schubert * The scheme goes like this. Both Alice and Bob have the same modulus n 13152b15cb3dSCy Schubert * and some random b as the group key. These values are computed and 13162b15cb3dSCy Schubert * distributed in advance via secret means, although only the group key 13172b15cb3dSCy Schubert * b is truly secret. Each has a private random private key u and public 13182b15cb3dSCy Schubert * key (u^-1)^b, although not necessarily the same ones. Bob and Alice 13192b15cb3dSCy Schubert * can regenerate the key pair from time to time without affecting 13202b15cb3dSCy Schubert * operations. The public key is conveyed on the certificate in an 13212b15cb3dSCy Schubert * extension field; the private key is never revealed. 13222b15cb3dSCy Schubert * 13232b15cb3dSCy Schubert * Alice rolls new random challenge r and sends to Bob in the GQ 13242b15cb3dSCy Schubert * request message. Bob rolls new random k, then computes y = k u^r mod 13252b15cb3dSCy Schubert * n and x = k^b mod n and sends (y, hash(x)) to Alice in the response 13262b15cb3dSCy Schubert * message. Besides making the response shorter, the hash makes it 13272b15cb3dSCy Schubert * effectivey impossible for an intruder to solve for b by observing 13282b15cb3dSCy Schubert * a number of these messages. 13292b15cb3dSCy Schubert * 13302b15cb3dSCy Schubert * Alice receives the response and computes y^b v^r mod n. After a bit 13312b15cb3dSCy Schubert * of algebra, this simplifies to k^b. If the hash of this result 13322b15cb3dSCy Schubert * matches hash(x), Alice knows that Bob has the group key b. The signed 13332b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 13342b15cb3dSCy Schubert * previously received in his certificate. 13359c2daa00SOllivier Robert */ 13369c2daa00SOllivier Robert /* 13372b15cb3dSCy Schubert * Generate Guillou-Quisquater (GQ) parameters file. 13389c2daa00SOllivier Robert */ 13399c2daa00SOllivier Robert EVP_PKEY * /* RSA cuckoo nest */ 13409c2daa00SOllivier Robert gen_gqkey( 13412b15cb3dSCy Schubert const char *id /* file name id */ 13429c2daa00SOllivier Robert ) 13439c2daa00SOllivier Robert { 13449c2daa00SOllivier Robert EVP_PKEY *pkey; /* private key */ 13459c2daa00SOllivier Robert RSA *rsa; /* RSA parameters */ 13469c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 13479c2daa00SOllivier Robert BIGNUM *u, *v, *g, *k, *r, *y; /* BN temps */ 13489c2daa00SOllivier Robert FILE *str; 13499c2daa00SOllivier Robert u_int temp; 1350f391d6bcSXin LI BIGNUM *b; 1351f391d6bcSXin LI const BIGNUM *n; 13529c2daa00SOllivier Robert 13539c2daa00SOllivier Robert /* 13542b15cb3dSCy Schubert * Generate RSA parameters for use as GQ parameters. 13559c2daa00SOllivier Robert */ 13562b15cb3dSCy Schubert fprintf(stderr, 13572b15cb3dSCy Schubert "Generating GQ parameters (%d bits)...\n", 13582b15cb3dSCy Schubert modulus2); 1359f391d6bcSXin LI rsa = genRsaKeyPair(modulus2, _UC("GQ")); 13602b15cb3dSCy Schubert fprintf(stderr, "\n"); 13612b15cb3dSCy Schubert if (rsa == NULL) { 13622b15cb3dSCy Schubert fprintf(stderr, "RSA generate keys fails\n%s\n", 13632b15cb3dSCy Schubert ERR_error_string(ERR_get_error(), NULL)); 13642b15cb3dSCy Schubert return (NULL); 13652b15cb3dSCy Schubert } 1366f391d6bcSXin LI RSA_get0_key(rsa, &n, NULL, NULL); 13672b15cb3dSCy Schubert u = BN_new(); v = BN_new(); g = BN_new(); 13682b15cb3dSCy Schubert k = BN_new(); r = BN_new(); y = BN_new(); 1369f391d6bcSXin LI b = BN_new(); 13702b15cb3dSCy Schubert 13712b15cb3dSCy Schubert /* 13722b15cb3dSCy Schubert * Generate the group key b, which is saved in the e member of 13732b15cb3dSCy Schubert * the RSA structure. The group key is transmitted to each group 13742b15cb3dSCy Schubert * member encrypted by the member private key. 13752b15cb3dSCy Schubert */ 13762b15cb3dSCy Schubert ctx = BN_CTX_new(); 1377f391d6bcSXin LI BN_rand(b, BN_num_bits(n), -1, 0); /* b */ 1378f391d6bcSXin LI BN_mod(b, b, n, ctx); 13799c2daa00SOllivier Robert 13809c2daa00SOllivier Robert /* 13819c2daa00SOllivier Robert * When generating his certificate, Bob rolls random private key 13822b15cb3dSCy Schubert * u, then computes inverse v = u^-1. 13839c2daa00SOllivier Robert */ 1384f391d6bcSXin LI BN_rand(u, BN_num_bits(n), -1, 0); /* u */ 1385f391d6bcSXin LI BN_mod(u, u, n, ctx); 1386f391d6bcSXin LI BN_mod_inverse(v, u, n, ctx); /* u^-1 mod n */ 1387f391d6bcSXin LI BN_mod_mul(k, v, u, n, ctx); 13889c2daa00SOllivier Robert 13899c2daa00SOllivier Robert /* 13909c2daa00SOllivier Robert * Bob computes public key v = (u^-1)^b, which is saved in an 13919c2daa00SOllivier Robert * extension field on his certificate. We check that u^b v = 13929c2daa00SOllivier Robert * 1 mod n. 13939c2daa00SOllivier Robert */ 1394f391d6bcSXin LI BN_mod_exp(v, v, b, n, ctx); 1395f391d6bcSXin LI BN_mod_exp(g, u, b, n, ctx); /* u^b */ 1396f391d6bcSXin LI BN_mod_mul(g, g, v, n, ctx); /* u^b (u^-1)^b */ 13979c2daa00SOllivier Robert temp = BN_is_one(g); 13989c2daa00SOllivier Robert fprintf(stderr, 13999c2daa00SOllivier Robert "Confirm u^b (u^-1)^b = 1 mod n: %s\n", temp ? "yes" : 14009c2daa00SOllivier Robert "no"); 14019c2daa00SOllivier Robert if (!temp) { 14029c2daa00SOllivier Robert BN_free(u); BN_free(v); 14039c2daa00SOllivier Robert BN_free(g); BN_free(k); BN_free(r); BN_free(y); 14049c2daa00SOllivier Robert BN_CTX_free(ctx); 14059c2daa00SOllivier Robert RSA_free(rsa); 14069c2daa00SOllivier Robert return (NULL); 14079c2daa00SOllivier Robert } 1408f391d6bcSXin LI /* setting 'u' and 'v' into a RSA object takes over ownership. 1409f391d6bcSXin LI * Since we use these values again, we have to pass in dupes, 1410f391d6bcSXin LI * or we'll corrupt the program! 1411f391d6bcSXin LI */ 1412f391d6bcSXin LI RSA_set0_factors(rsa, BN_dup(u), BN_dup(v)); 14139c2daa00SOllivier Robert 14149c2daa00SOllivier Robert /* 14159c2daa00SOllivier Robert * Here is a trial run of the protocol. First, Alice rolls 14162b15cb3dSCy Schubert * random nonce r mod n and sends it to Bob. She needs only n 14172b15cb3dSCy Schubert * from parameters. 14189c2daa00SOllivier Robert */ 1419f391d6bcSXin LI BN_rand(r, BN_num_bits(n), -1, 0); /* r */ 1420f391d6bcSXin LI BN_mod(r, r, n, ctx); 14219c2daa00SOllivier Robert 14229c2daa00SOllivier Robert /* 14232b15cb3dSCy Schubert * Bob rolls random nonce k mod n, computes y = k u^r mod n and 14242b15cb3dSCy Schubert * g = k^b mod n, then sends (y, g) to Alice. He needs n, u, b 14252b15cb3dSCy Schubert * from parameters and r from Alice. 14269c2daa00SOllivier Robert */ 1427f391d6bcSXin LI BN_rand(k, BN_num_bits(n), -1, 0); /* k */ 1428f391d6bcSXin LI BN_mod(k, k, n, ctx); 1429f391d6bcSXin LI BN_mod_exp(y, u, r, n, ctx); /* u^r mod n */ 1430f391d6bcSXin LI BN_mod_mul(y, k, y, n, ctx); /* y = k u^r mod n */ 1431f391d6bcSXin LI BN_mod_exp(g, k, b, n, ctx); /* g = k^b mod n */ 14329c2daa00SOllivier Robert 14339c2daa00SOllivier Robert /* 14342b15cb3dSCy Schubert * Alice verifies g = v^r y^b mod n to confirm that Bob has 14352b15cb3dSCy Schubert * private key u. She needs n, g from parameters, public key v = 14362b15cb3dSCy Schubert * (u^-1)^b from the certificate, (y, g) from Bob and the 14372b15cb3dSCy Schubert * original r. We omit the detaul here that only the hash of g 14382b15cb3dSCy Schubert * is sent. 14399c2daa00SOllivier Robert */ 1440f391d6bcSXin LI BN_mod_exp(v, v, r, n, ctx); /* v^r mod n */ 1441f391d6bcSXin LI BN_mod_exp(y, y, b, n, ctx); /* y^b mod n */ 1442f391d6bcSXin LI BN_mod_mul(y, v, y, n, ctx); /* v^r y^b mod n */ 14439c2daa00SOllivier Robert temp = BN_cmp(y, g); 14449c2daa00SOllivier Robert fprintf(stderr, "Confirm g^k = v^r y^b mod n: %s\n", temp == 0 ? 14459c2daa00SOllivier Robert "yes" : "no"); 14469c2daa00SOllivier Robert BN_CTX_free(ctx); BN_free(u); BN_free(v); 14479c2daa00SOllivier Robert BN_free(g); BN_free(k); BN_free(r); BN_free(y); 14489c2daa00SOllivier Robert if (temp != 0) { 14499c2daa00SOllivier Robert RSA_free(rsa); 14509c2daa00SOllivier Robert return (NULL); 14519c2daa00SOllivier Robert } 14529c2daa00SOllivier Robert 14539c2daa00SOllivier Robert /* 14542b15cb3dSCy Schubert * Write the GQ parameter file as an encrypted RSA private key 14552b15cb3dSCy Schubert * encoded in PEM. 14569c2daa00SOllivier Robert * 14579c2daa00SOllivier Robert * n modulus n 14589c2daa00SOllivier Robert * e group key b 14592b15cb3dSCy Schubert * d not used 14609c2daa00SOllivier Robert * p private key u 14619c2daa00SOllivier Robert * q public key (u^-1)^b 14622b15cb3dSCy Schubert * dmp1 not used 14632b15cb3dSCy Schubert * dmq1 not used 14642b15cb3dSCy Schubert * iqmp not used 14659c2daa00SOllivier Robert */ 1466f391d6bcSXin LI RSA_set0_key(rsa, NULL, b, BN_dup(BN_value_one())); 1467f391d6bcSXin LI RSA_set0_crt_params(rsa, BN_dup(BN_value_one()), BN_dup(BN_value_one()), 1468f391d6bcSXin LI BN_dup(BN_value_one())); 14692b15cb3dSCy Schubert str = fheader("GQkey", id, groupname); 14709c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 14719c2daa00SOllivier Robert EVP_PKEY_assign_RSA(pkey, rsa); 14722b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 14732b15cb3dSCy Schubert passwd1); 14749c2daa00SOllivier Robert fclose(str); 14759c2daa00SOllivier Robert if (debug) 14762b15cb3dSCy Schubert RSA_print_fp(stderr, rsa, 0); 14779c2daa00SOllivier Robert return (pkey); 14789c2daa00SOllivier Robert } 14799c2daa00SOllivier Robert 14809c2daa00SOllivier Robert 14819c2daa00SOllivier Robert /* 14822b15cb3dSCy Schubert *********************************************************************** 14832b15cb3dSCy Schubert * * 14842b15cb3dSCy Schubert * The following routines implement the Mu-Varadharajan (MV) identity * 14852b15cb3dSCy Schubert * scheme * 14862b15cb3dSCy Schubert * * 14872b15cb3dSCy Schubert *********************************************************************** 14889c2daa00SOllivier Robert * 14892b15cb3dSCy Schubert * The Mu-Varadharajan (MV) cryptosystem was originally intended when 14902b15cb3dSCy Schubert * servers broadcast messages to clients, but clients never send 14912b15cb3dSCy Schubert * messages to servers. There is one encryption key for the server and a 14922b15cb3dSCy Schubert * separate decryption key for each client. It operated something like a 14939c2daa00SOllivier Robert * pay-per-view satellite broadcasting system where the session key is 14949c2daa00SOllivier Robert * encrypted by the broadcaster and the decryption keys are held in a 14952b15cb3dSCy Schubert * tamperproof set-top box. 14969c2daa00SOllivier Robert * 14979c2daa00SOllivier Robert * The MV parameters and private encryption key hide in a DSA cuckoo 14989c2daa00SOllivier Robert * structure which uses the same parameters, but generated in a 14999c2daa00SOllivier Robert * different way. The values are used in an encryption scheme similar to 15009c2daa00SOllivier Robert * El Gamal cryptography and a polynomial formed from the expansion of 15019c2daa00SOllivier Robert * product terms (x - x[j]), as described in Mu, Y., and V. 15029c2daa00SOllivier Robert * Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001, 15039c2daa00SOllivier Robert * 223-231. The paper has significant errors and serious omissions. 15049c2daa00SOllivier Robert * 15052b15cb3dSCy Schubert * Let q be the product of n distinct primes s1[j] (j = 1...n), where 15062b15cb3dSCy Schubert * each s1[j] has m significant bits. Let p be a prime p = 2 * q + 1, so 15072b15cb3dSCy Schubert * that q and each s1[j] divide p - 1 and p has M = n * m + 1 15089c2daa00SOllivier Robert * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1) 15099c2daa00SOllivier Robert * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then 15109c2daa00SOllivier Robert * project into Zp* as exponents of g. Sometimes we have to compute an 15119c2daa00SOllivier Robert * inverse b^-1 of random b in Zq, but for that purpose we require 15129c2daa00SOllivier Robert * gcd(b, q) = 1. We expect M to be in the 500-bit range and n 15132b15cb3dSCy Schubert * relatively small, like 30. These are the parameters of the scheme and 15142b15cb3dSCy Schubert * they are expensive to compute. 15159c2daa00SOllivier Robert * 15169c2daa00SOllivier Robert * We set up an instance of the scheme as follows. A set of random 15179c2daa00SOllivier Robert * values x[j] mod q (j = 1...n), are generated as the zeros of a 15189c2daa00SOllivier Robert * polynomial of order n. The product terms (x - x[j]) are expanded to 15199c2daa00SOllivier Robert * form coefficients a[i] mod q (i = 0...n) in powers of x. These are 15209c2daa00SOllivier Robert * used as exponents of the generator g mod p to generate the private 15219c2daa00SOllivier Robert * encryption key A. The pair (gbar, ghat) of public server keys and the 15229c2daa00SOllivier Robert * pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used 15239c2daa00SOllivier Robert * to construct the decryption keys. The devil is in the details. 15249c2daa00SOllivier Robert * 15252b15cb3dSCy Schubert * This routine generates a private server encryption file including the 15262b15cb3dSCy Schubert * private encryption key E and partial decryption keys gbar and ghat. 15272b15cb3dSCy Schubert * It then generates public client decryption files including the public 15282b15cb3dSCy Schubert * keys xbar[j] and xhat[j] for each client j. The partial decryption 15292b15cb3dSCy Schubert * files are used to compute the inverse of E. These values are suitably 15302b15cb3dSCy Schubert * blinded so secrets are not revealed. 15319c2daa00SOllivier Robert * 15329c2daa00SOllivier Robert * The distinguishing characteristic of this scheme is the capability to 15339c2daa00SOllivier Robert * revoke keys. Included in the calculation of E, gbar and ghat is the 15342b15cb3dSCy Schubert * product s = prod(s1[j]) (j = 1...n) above. If the factor s1[j] is 15359c2daa00SOllivier Robert * subsequently removed from the product and E, gbar and ghat 15369c2daa00SOllivier Robert * recomputed, the jth client will no longer be able to compute E^-1 and 15372b15cb3dSCy Schubert * thus unable to decrypt the messageblock. 15382b15cb3dSCy Schubert * 15392b15cb3dSCy Schubert * How it works 15402b15cb3dSCy Schubert * 15412b15cb3dSCy Schubert * The scheme goes like this. Bob has the server values (p, E, q, 15422b15cb3dSCy Schubert * gbar, ghat) and Alice has the client values (p, xbar, xhat). 15432b15cb3dSCy Schubert * 15442b15cb3dSCy Schubert * Alice rolls new random nonce r mod p and sends to Bob in the MV 15452b15cb3dSCy Schubert * request message. Bob rolls random nonce k mod q, encrypts y = r E^k 15462b15cb3dSCy Schubert * mod p and sends (y, gbar^k, ghat^k) to Alice. 15472b15cb3dSCy Schubert * 15482b15cb3dSCy Schubert * Alice receives the response and computes the inverse (E^k)^-1 from 15492b15cb3dSCy Schubert * the partial decryption keys gbar^k, ghat^k, xbar and xhat. She then 15502b15cb3dSCy Schubert * decrypts y and verifies it matches the original r. The signed 15512b15cb3dSCy Schubert * response binds this knowledge to Bob's private key and the public key 15522b15cb3dSCy Schubert * previously received in his certificate. 15539c2daa00SOllivier Robert */ 15549c2daa00SOllivier Robert EVP_PKEY * /* DSA cuckoo nest */ 15552b15cb3dSCy Schubert gen_mvkey( 15562b15cb3dSCy Schubert const char *id, /* file name id */ 15572b15cb3dSCy Schubert EVP_PKEY **evpars /* parameter list pointer */ 15589c2daa00SOllivier Robert ) 15599c2daa00SOllivier Robert { 15602b15cb3dSCy Schubert EVP_PKEY *pkey, *pkey1; /* private keys */ 15612b15cb3dSCy Schubert DSA *dsa, *dsa2, *sdsa; /* DSA parameters */ 15629c2daa00SOllivier Robert BN_CTX *ctx; /* BN working space */ 15632b15cb3dSCy Schubert BIGNUM *a[MVMAX]; /* polynomial coefficient vector */ 1564f391d6bcSXin LI BIGNUM *gs[MVMAX]; /* public key vector */ 15652b15cb3dSCy Schubert BIGNUM *s1[MVMAX]; /* private enabling keys */ 15662b15cb3dSCy Schubert BIGNUM *x[MVMAX]; /* polynomial zeros vector */ 15672b15cb3dSCy Schubert BIGNUM *xbar[MVMAX], *xhat[MVMAX]; /* private keys vector */ 15689c2daa00SOllivier Robert BIGNUM *b; /* group key */ 15699c2daa00SOllivier Robert BIGNUM *b1; /* inverse group key */ 15702b15cb3dSCy Schubert BIGNUM *s; /* enabling key */ 15719c2daa00SOllivier Robert BIGNUM *biga; /* master encryption key */ 15729c2daa00SOllivier Robert BIGNUM *bige; /* session encryption key */ 15739c2daa00SOllivier Robert BIGNUM *gbar, *ghat; /* public key */ 15749c2daa00SOllivier Robert BIGNUM *u, *v, *w; /* BN scratch */ 1575f391d6bcSXin LI BIGNUM *p, *q, *g, *priv_key, *pub_key; 15769c2daa00SOllivier Robert int i, j, n; 15779c2daa00SOllivier Robert FILE *str; 15789c2daa00SOllivier Robert u_int temp; 15799c2daa00SOllivier Robert 15809c2daa00SOllivier Robert /* 15819c2daa00SOllivier Robert * Generate MV parameters. 15829c2daa00SOllivier Robert * 15839c2daa00SOllivier Robert * The object is to generate a multiplicative group Zp* modulo a 15849c2daa00SOllivier Robert * prime p and a subset Zq mod q, where q is the product of n 15852b15cb3dSCy Schubert * distinct primes s1[j] (j = 1...n) and q divides p - 1. We 15862b15cb3dSCy Schubert * first generate n m-bit primes, where the product n m is in 15872b15cb3dSCy Schubert * the order of 512 bits. One or more of these may have to be 15882b15cb3dSCy Schubert * replaced later. As a practical matter, it is tough to find 15892b15cb3dSCy Schubert * more than 31 distinct primes for 512 bits or 61 primes for 15902b15cb3dSCy Schubert * 1024 bits. The latter can take several hundred iterations 15919c2daa00SOllivier Robert * and several minutes on a Sun Blade 1000. 15929c2daa00SOllivier Robert */ 15939c2daa00SOllivier Robert n = nkeys; 15949c2daa00SOllivier Robert fprintf(stderr, 15959c2daa00SOllivier Robert "Generating MV parameters for %d keys (%d bits)...\n", n, 15962b15cb3dSCy Schubert modulus2 / n); 15979c2daa00SOllivier Robert ctx = BN_CTX_new(); u = BN_new(); v = BN_new(); w = BN_new(); 15989c2daa00SOllivier Robert b = BN_new(); b1 = BN_new(); 15995e91a9b7SOllivier Robert dsa = DSA_new(); 1600f391d6bcSXin LI p = BN_new(); q = BN_new(); g = BN_new(); 1601f391d6bcSXin LI priv_key = BN_new(); pub_key = BN_new(); 16029c2daa00SOllivier Robert temp = 0; 16039c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 16042b15cb3dSCy Schubert s1[j] = BN_new(); 16059c2daa00SOllivier Robert while (1) { 1606f391d6bcSXin LI BN_generate_prime_ex(s1[j], modulus2 / n, 0, 16079c2daa00SOllivier Robert NULL, NULL, NULL); 16089c2daa00SOllivier Robert for (i = 1; i < j; i++) { 16099c2daa00SOllivier Robert if (BN_cmp(s1[i], s1[j]) == 0) 16109c2daa00SOllivier Robert break; 16119c2daa00SOllivier Robert } 16129c2daa00SOllivier Robert if (i == j) 16139c2daa00SOllivier Robert break; 16149c2daa00SOllivier Robert temp++; 16159c2daa00SOllivier Robert } 16169c2daa00SOllivier Robert } 16172b15cb3dSCy Schubert fprintf(stderr, "Birthday keys regenerated %d\n", temp); 16189c2daa00SOllivier Robert 16199c2daa00SOllivier Robert /* 16209c2daa00SOllivier Robert * Compute the modulus q as the product of the primes. Compute 16219c2daa00SOllivier Robert * the modulus p as 2 * q + 1 and test p for primality. If p 16229c2daa00SOllivier Robert * is composite, replace one of the primes with a new distinct 16239c2daa00SOllivier Robert * one and try again. Note that q will hardly be a secret since 16242b15cb3dSCy Schubert * we have to reveal p to servers, but not clients. However, 16259c2daa00SOllivier Robert * factoring q to find the primes should be adequately hard, as 16269c2daa00SOllivier Robert * this is the same problem considered hard in RSA. Question: is 16279c2daa00SOllivier Robert * it as hard to find n small prime factors totalling n bits as 16289c2daa00SOllivier Robert * it is to find two large prime factors totalling n bits? 16299c2daa00SOllivier Robert * Remember, the bad guy doesn't know n. 16309c2daa00SOllivier Robert */ 16319c2daa00SOllivier Robert temp = 0; 16329c2daa00SOllivier Robert while (1) { 1633f391d6bcSXin LI BN_one(q); 16349c2daa00SOllivier Robert for (j = 1; j <= n; j++) 1635f391d6bcSXin LI BN_mul(q, q, s1[j], ctx); 1636f391d6bcSXin LI BN_copy(p, q); 1637f391d6bcSXin LI BN_add(p, p, p); 1638f391d6bcSXin LI BN_add_word(p, 1); 1639f391d6bcSXin LI if (BN_is_prime_ex(p, BN_prime_checks, ctx, NULL)) 16409c2daa00SOllivier Robert break; 16419c2daa00SOllivier Robert 16422b15cb3dSCy Schubert temp++; 16439c2daa00SOllivier Robert j = temp % n + 1; 16449c2daa00SOllivier Robert while (1) { 1645f391d6bcSXin LI BN_generate_prime_ex(u, modulus2 / n, 0, 1646f391d6bcSXin LI NULL, NULL, NULL); 16479c2daa00SOllivier Robert for (i = 1; i <= n; i++) { 16489c2daa00SOllivier Robert if (BN_cmp(u, s1[i]) == 0) 16499c2daa00SOllivier Robert break; 16509c2daa00SOllivier Robert } 16519c2daa00SOllivier Robert if (i > n) 16529c2daa00SOllivier Robert break; 16539c2daa00SOllivier Robert } 16549c2daa00SOllivier Robert BN_copy(s1[j], u); 16559c2daa00SOllivier Robert } 16562b15cb3dSCy Schubert fprintf(stderr, "Defective keys regenerated %d\n", temp); 16579c2daa00SOllivier Robert 16589c2daa00SOllivier Robert /* 16599c2daa00SOllivier Robert * Compute the generator g using a random roll such that 16609c2daa00SOllivier Robert * gcd(g, p - 1) = 1 and g^q = 1. This is a generator of p, not 16612b15cb3dSCy Schubert * q. This may take several iterations. 16629c2daa00SOllivier Robert */ 1663f391d6bcSXin LI BN_copy(v, p); 16649c2daa00SOllivier Robert BN_sub_word(v, 1); 16659c2daa00SOllivier Robert while (1) { 1666f391d6bcSXin LI BN_rand(g, BN_num_bits(p) - 1, 0, 0); 1667f391d6bcSXin LI BN_mod(g, g, p, ctx); 1668f391d6bcSXin LI BN_gcd(u, g, v, ctx); 16699c2daa00SOllivier Robert if (!BN_is_one(u)) 16709c2daa00SOllivier Robert continue; 16719c2daa00SOllivier Robert 1672f391d6bcSXin LI BN_mod_exp(u, g, q, p, ctx); 16739c2daa00SOllivier Robert if (BN_is_one(u)) 16749c2daa00SOllivier Robert break; 16759c2daa00SOllivier Robert } 16769c2daa00SOllivier Robert 1677f391d6bcSXin LI DSA_set0_pqg(dsa, p, q, g); 1678f391d6bcSXin LI 16799c2daa00SOllivier Robert /* 16809c2daa00SOllivier Robert * Setup is now complete. Roll random polynomial roots x[j] 16812b15cb3dSCy Schubert * (j = 1...n) for all j. While it may not be strictly 16829c2daa00SOllivier Robert * necessary, Make sure each root has no factors in common with 16839c2daa00SOllivier Robert * q. 16849c2daa00SOllivier Robert */ 16859c2daa00SOllivier Robert fprintf(stderr, 16869c2daa00SOllivier Robert "Generating polynomial coefficients for %d roots (%d bits)\n", 1687f391d6bcSXin LI n, BN_num_bits(q)); 16889c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 16899c2daa00SOllivier Robert x[j] = BN_new(); 16902b15cb3dSCy Schubert 16919c2daa00SOllivier Robert while (1) { 1692f391d6bcSXin LI BN_rand(x[j], BN_num_bits(q), 0, 0); 1693f391d6bcSXin LI BN_mod(x[j], x[j], q, ctx); 1694f391d6bcSXin LI BN_gcd(u, x[j], q, ctx); 16959c2daa00SOllivier Robert if (BN_is_one(u)) 16969c2daa00SOllivier Robert break; 16979c2daa00SOllivier Robert } 16989c2daa00SOllivier Robert } 16999c2daa00SOllivier Robert 17009c2daa00SOllivier Robert /* 17019c2daa00SOllivier Robert * Generate polynomial coefficients a[i] (i = 0...n) from the 17029c2daa00SOllivier Robert * expansion of root products (x - x[j]) mod q for all j. The 17039c2daa00SOllivier Robert * method is a present from Charlie Boncelet. 17049c2daa00SOllivier Robert */ 17059c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 17069c2daa00SOllivier Robert a[i] = BN_new(); 17079c2daa00SOllivier Robert BN_one(a[i]); 17089c2daa00SOllivier Robert } 17099c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17109c2daa00SOllivier Robert BN_zero(w); 17119c2daa00SOllivier Robert for (i = 0; i < j; i++) { 1712f391d6bcSXin LI BN_copy(u, q); 1713f391d6bcSXin LI BN_mod_mul(v, a[i], x[j], q, ctx); 17149c2daa00SOllivier Robert BN_sub(u, u, v); 17159c2daa00SOllivier Robert BN_add(u, u, w); 17169c2daa00SOllivier Robert BN_copy(w, a[i]); 1717f391d6bcSXin LI BN_mod(a[i], u, q, ctx); 17189c2daa00SOllivier Robert } 17199c2daa00SOllivier Robert } 17209c2daa00SOllivier Robert 17219c2daa00SOllivier Robert /* 1722f391d6bcSXin LI * Generate gs[i] = g^a[i] mod p for all i and the generator g. 17239c2daa00SOllivier Robert */ 17249c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 1725f391d6bcSXin LI gs[i] = BN_new(); 1726f391d6bcSXin LI BN_mod_exp(gs[i], g, a[i], p, ctx); 17279c2daa00SOllivier Robert } 17289c2daa00SOllivier Robert 17299c2daa00SOllivier Robert /* 1730f391d6bcSXin LI * Verify prod(gs[i]^(a[i] x[j]^i)) = 1 for all i, j. Note the 1731f391d6bcSXin LI * a[i] x[j]^i exponent is computed mod q, but the gs[i] is 17322b15cb3dSCy Schubert * computed mod p. also note the expression given in the paper 17332b15cb3dSCy Schubert * is incorrect. 17349c2daa00SOllivier Robert */ 17359c2daa00SOllivier Robert temp = 1; 17369c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17379c2daa00SOllivier Robert BN_one(u); 17389c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 17399c2daa00SOllivier Robert BN_set_word(v, i); 1740f391d6bcSXin LI BN_mod_exp(v, x[j], v, q, ctx); 1741f391d6bcSXin LI BN_mod_mul(v, v, a[i], q, ctx); 1742f391d6bcSXin LI BN_mod_exp(v, g, v, p, ctx); 1743f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 17449c2daa00SOllivier Robert } 17459c2daa00SOllivier Robert if (!BN_is_one(u)) 17469c2daa00SOllivier Robert temp = 0; 17479c2daa00SOllivier Robert } 17489c2daa00SOllivier Robert fprintf(stderr, 1749f391d6bcSXin LI "Confirm prod(gs[i]^(x[j]^i)) = 1 for all i, j: %s\n", temp ? 17509c2daa00SOllivier Robert "yes" : "no"); 17519c2daa00SOllivier Robert if (!temp) { 17529c2daa00SOllivier Robert return (NULL); 17539c2daa00SOllivier Robert } 17549c2daa00SOllivier Robert 17559c2daa00SOllivier Robert /* 17569c2daa00SOllivier Robert * Make private encryption key A. Keep it around for awhile, 17579c2daa00SOllivier Robert * since it is expensive to compute. 17589c2daa00SOllivier Robert */ 17599c2daa00SOllivier Robert biga = BN_new(); 17602b15cb3dSCy Schubert 17619c2daa00SOllivier Robert BN_one(biga); 17629c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17639c2daa00SOllivier Robert for (i = 0; i < n; i++) { 17649c2daa00SOllivier Robert BN_set_word(v, i); 1765f391d6bcSXin LI BN_mod_exp(v, x[j], v, q, ctx); 1766f391d6bcSXin LI BN_mod_exp(v, gs[i], v, p, ctx); 1767f391d6bcSXin LI BN_mod_mul(biga, biga, v, p, ctx); 17689c2daa00SOllivier Robert } 17699c2daa00SOllivier Robert } 17709c2daa00SOllivier Robert 17719c2daa00SOllivier Robert /* 17729c2daa00SOllivier Robert * Roll private random group key b mod q (0 < b < q), where 17732b15cb3dSCy Schubert * gcd(b, q) = 1 to guarantee b^-1 exists, then compute b^-1 17749c2daa00SOllivier Robert * mod q. If b is changed, the client keys must be recomputed. 17759c2daa00SOllivier Robert */ 17769c2daa00SOllivier Robert while (1) { 1777f391d6bcSXin LI BN_rand(b, BN_num_bits(q), 0, 0); 1778f391d6bcSXin LI BN_mod(b, b, q, ctx); 1779f391d6bcSXin LI BN_gcd(u, b, q, ctx); 17809c2daa00SOllivier Robert if (BN_is_one(u)) 17819c2daa00SOllivier Robert break; 17829c2daa00SOllivier Robert } 1783f391d6bcSXin LI BN_mod_inverse(b1, b, q, ctx); 17849c2daa00SOllivier Robert 17859c2daa00SOllivier Robert /* 17869c2daa00SOllivier Robert * Make private client keys (xbar[j], xhat[j]) for all j. Note 17872b15cb3dSCy Schubert * that the keys for the jth client do not s1[j] or the product 17882b15cb3dSCy Schubert * s1[j]) (j = 1...n) which is q by construction. 17892b15cb3dSCy Schubert * 17902b15cb3dSCy Schubert * Compute the factor w such that w s1[j] = s1[j] for all j. The 17912b15cb3dSCy Schubert * easy way to do this is to compute (q + s1[j]) / s1[j]. 17922b15cb3dSCy Schubert * Exercise for the student: prove the remainder is always zero. 17939c2daa00SOllivier Robert */ 17949c2daa00SOllivier Robert for (j = 1; j <= n; j++) { 17959c2daa00SOllivier Robert xbar[j] = BN_new(); xhat[j] = BN_new(); 17962b15cb3dSCy Schubert 1797f391d6bcSXin LI BN_add(w, q, s1[j]); 17982b15cb3dSCy Schubert BN_div(w, u, w, s1[j], ctx); 17999c2daa00SOllivier Robert BN_zero(xbar[j]); 18009c2daa00SOllivier Robert BN_set_word(v, n); 18019c2daa00SOllivier Robert for (i = 1; i <= n; i++) { 18029c2daa00SOllivier Robert if (i == j) 18039c2daa00SOllivier Robert continue; 18042b15cb3dSCy Schubert 1805f391d6bcSXin LI BN_mod_exp(u, x[i], v, q, ctx); 18069c2daa00SOllivier Robert BN_add(xbar[j], xbar[j], u); 18079c2daa00SOllivier Robert } 1808f391d6bcSXin LI BN_mod_mul(xbar[j], xbar[j], b1, q, ctx); 1809f391d6bcSXin LI BN_mod_exp(xhat[j], x[j], v, q, ctx); 1810f391d6bcSXin LI BN_mod_mul(xhat[j], xhat[j], w, q, ctx); 18119c2daa00SOllivier Robert } 18129c2daa00SOllivier Robert 18139c2daa00SOllivier Robert /* 18142b15cb3dSCy Schubert * We revoke client j by dividing q by s1[j]. The quotient 18152b15cb3dSCy Schubert * becomes the enabling key s. Note we always have to revoke 18162b15cb3dSCy Schubert * one key; otherwise, the plaintext and cryptotext would be 18172b15cb3dSCy Schubert * identical. For the present there are no provisions to revoke 18182b15cb3dSCy Schubert * additional keys, so we sail on with only token revocations. 18199c2daa00SOllivier Robert */ 18202b15cb3dSCy Schubert s = BN_new(); 1821f391d6bcSXin LI BN_copy(s, q); 18222b15cb3dSCy Schubert BN_div(s, u, s, s1[n], ctx); 18239c2daa00SOllivier Robert 18249c2daa00SOllivier Robert /* 18252b15cb3dSCy Schubert * For each combination of clients to be revoked, make private 18262b15cb3dSCy Schubert * encryption key E = A^s and partial decryption keys gbar = g^s 18272b15cb3dSCy Schubert * and ghat = g^(s b), all mod p. The servers use these keys to 18282b15cb3dSCy Schubert * compute the session encryption key and partial decryption 18292b15cb3dSCy Schubert * keys. These values must be regenerated if the enabling key is 18302b15cb3dSCy Schubert * changed. 18319c2daa00SOllivier Robert */ 18329c2daa00SOllivier Robert bige = BN_new(); gbar = BN_new(); ghat = BN_new(); 1833f391d6bcSXin LI BN_mod_exp(bige, biga, s, p, ctx); 1834f391d6bcSXin LI BN_mod_exp(gbar, g, s, p, ctx); 1835f391d6bcSXin LI BN_mod_mul(v, s, b, q, ctx); 1836f391d6bcSXin LI BN_mod_exp(ghat, g, v, p, ctx); 18379c2daa00SOllivier Robert 18389c2daa00SOllivier Robert /* 18392b15cb3dSCy Schubert * Notes: We produce the key media in three steps. The first 18402b15cb3dSCy Schubert * step is to generate the system parameters p, q, g, b, A and 18412b15cb3dSCy Schubert * the enabling keys s1[j]. Associated with each s1[j] are 18422b15cb3dSCy Schubert * parameters xbar[j] and xhat[j]. All of these parameters are 18432b15cb3dSCy Schubert * retained in a data structure protecteted by the trusted-agent 18442b15cb3dSCy Schubert * password. The p, xbar[j] and xhat[j] paremeters are 18452b15cb3dSCy Schubert * distributed to the j clients. When the client keys are to be 18462b15cb3dSCy Schubert * activated, the enabled keys are multipied together to form 18472b15cb3dSCy Schubert * the master enabling key s. This and the other parameters are 18482b15cb3dSCy Schubert * used to compute the server encryption key E and the partial 18492b15cb3dSCy Schubert * decryption keys gbar and ghat. 18509c2daa00SOllivier Robert * 18512b15cb3dSCy Schubert * In the identity exchange the client rolls random r and sends 18522b15cb3dSCy Schubert * it to the server. The server rolls random k, which is used 18532b15cb3dSCy Schubert * only once, then computes the session key E^k and partial 18542b15cb3dSCy Schubert * decryption keys gbar^k and ghat^k. The server sends the 18552b15cb3dSCy Schubert * encrypted r along with gbar^k and ghat^k to the client. The 18562b15cb3dSCy Schubert * client completes the decryption and verifies it matches r. 18579c2daa00SOllivier Robert */ 18589c2daa00SOllivier Robert /* 18592b15cb3dSCy Schubert * Write the MV trusted-agent parameters and keys as a DSA 18602b15cb3dSCy Schubert * private key encoded in PEM. 18619c2daa00SOllivier Robert * 18629c2daa00SOllivier Robert * p modulus p 18632b15cb3dSCy Schubert * q modulus q 18642b15cb3dSCy Schubert * g generator g 18652b15cb3dSCy Schubert * priv_key A mod p 18662b15cb3dSCy Schubert * pub_key b mod q 18672b15cb3dSCy Schubert * (remaining values are not used) 18689c2daa00SOllivier Robert */ 18692b15cb3dSCy Schubert i = 0; 18702b15cb3dSCy Schubert str = fheader("MVta", "mvta", groupname); 18712b15cb3dSCy Schubert fprintf(stderr, "Generating MV trusted-authority keys\n"); 1872f391d6bcSXin LI BN_copy(priv_key, biga); 1873f391d6bcSXin LI BN_copy(pub_key, b); 1874f391d6bcSXin LI DSA_set0_key(dsa, pub_key, priv_key); 18759c2daa00SOllivier Robert pkey = EVP_PKEY_new(); 18769c2daa00SOllivier Robert EVP_PKEY_assign_DSA(pkey, dsa); 18772b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey, cipher, NULL, 0, NULL, 18782b15cb3dSCy Schubert passwd1); 18792b15cb3dSCy Schubert evpars[i++] = pkey; 18809c2daa00SOllivier Robert if (debug) 18812b15cb3dSCy Schubert DSA_print_fp(stderr, dsa, 0); 18829c2daa00SOllivier Robert 18839c2daa00SOllivier Robert /* 18842b15cb3dSCy Schubert * Append the MV server parameters and keys as a DSA key encoded 18852b15cb3dSCy Schubert * in PEM. 18862b15cb3dSCy Schubert * 18872b15cb3dSCy Schubert * p modulus p 18882b15cb3dSCy Schubert * q modulus q (used only when generating k) 18892b15cb3dSCy Schubert * g bige 18902b15cb3dSCy Schubert * priv_key gbar 18912b15cb3dSCy Schubert * pub_key ghat 18922b15cb3dSCy Schubert * (remaining values are not used) 18939c2daa00SOllivier Robert */ 18942b15cb3dSCy Schubert fprintf(stderr, "Generating MV server keys\n"); 18952b15cb3dSCy Schubert dsa2 = DSA_new(); 1896f391d6bcSXin LI DSA_set0_pqg(dsa2, BN_dup(p), BN_dup(q), BN_dup(bige)); 1897f391d6bcSXin LI DSA_set0_key(dsa2, BN_dup(ghat), BN_dup(gbar)); 18982b15cb3dSCy Schubert pkey1 = EVP_PKEY_new(); 18992b15cb3dSCy Schubert EVP_PKEY_assign_DSA(pkey1, dsa2); 19002b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey1, cipher, NULL, 0, NULL, 19012b15cb3dSCy Schubert passwd1); 19022b15cb3dSCy Schubert evpars[i++] = pkey1; 19032b15cb3dSCy Schubert if (debug) 19042b15cb3dSCy Schubert DSA_print_fp(stderr, dsa2, 0); 19059c2daa00SOllivier Robert 19069c2daa00SOllivier Robert /* 19072b15cb3dSCy Schubert * Append the MV client parameters for each client j as DSA keys 19082b15cb3dSCy Schubert * encoded in PEM. 19099c2daa00SOllivier Robert * 19109c2daa00SOllivier Robert * p modulus p 19119c2daa00SOllivier Robert * priv_key xbar[j] mod q 19129c2daa00SOllivier Robert * pub_key xhat[j] mod q 19139c2daa00SOllivier Robert * (remaining values are not used) 19149c2daa00SOllivier Robert */ 19152b15cb3dSCy Schubert fprintf(stderr, "Generating %d MV client keys\n", n); 19162b15cb3dSCy Schubert for (j = 1; j <= n; j++) { 19172b15cb3dSCy Schubert sdsa = DSA_new(); 1918f391d6bcSXin LI DSA_set0_pqg(sdsa, BN_dup(p), BN_dup(BN_value_one()), 1919f391d6bcSXin LI BN_dup(BN_value_one())); 1920f391d6bcSXin LI DSA_set0_key(sdsa, BN_dup(xhat[j]), BN_dup(xbar[j])); 19215e91a9b7SOllivier Robert pkey1 = EVP_PKEY_new(); 19225e91a9b7SOllivier Robert EVP_PKEY_set1_DSA(pkey1, sdsa); 19232b15cb3dSCy Schubert PEM_write_PKCS8PrivateKey(str, pkey1, cipher, NULL, 0, 19242b15cb3dSCy Schubert NULL, passwd1); 19252b15cb3dSCy Schubert evpars[i++] = pkey1; 19269c2daa00SOllivier Robert if (debug) 19272b15cb3dSCy Schubert DSA_print_fp(stderr, sdsa, 0); 19282b15cb3dSCy Schubert 19292b15cb3dSCy Schubert /* 1930f391d6bcSXin LI * The product (gbar^k)^xbar[j] (ghat^k)^xhat[j] and E 19312b15cb3dSCy Schubert * are inverses of each other. We check that the product 19322b15cb3dSCy Schubert * is one for each client except the ones that have been 19332b15cb3dSCy Schubert * revoked. 19342b15cb3dSCy Schubert */ 1935f391d6bcSXin LI BN_mod_exp(v, gbar, xhat[j], p, ctx); 1936f391d6bcSXin LI BN_mod_exp(u, ghat, xbar[j], p, ctx); 1937f391d6bcSXin LI BN_mod_mul(u, u, v, p, ctx); 1938f391d6bcSXin LI BN_mod_mul(u, u, bige, p, ctx); 19392b15cb3dSCy Schubert if (!BN_is_one(u)) { 19402b15cb3dSCy Schubert fprintf(stderr, "Revoke key %d\n", j); 19412b15cb3dSCy Schubert continue; 19429c2daa00SOllivier Robert } 19432b15cb3dSCy Schubert } 19442b15cb3dSCy Schubert evpars[i++] = NULL; 19452b15cb3dSCy Schubert fclose(str); 19469c2daa00SOllivier Robert 19479c2daa00SOllivier Robert /* 19489c2daa00SOllivier Robert * Free the countries. 19499c2daa00SOllivier Robert */ 19509c2daa00SOllivier Robert for (i = 0; i <= n; i++) { 1951f391d6bcSXin LI BN_free(a[i]); BN_free(gs[i]); 19529c2daa00SOllivier Robert } 19532b15cb3dSCy Schubert for (j = 1; j <= n; j++) { 19542b15cb3dSCy Schubert BN_free(x[j]); BN_free(xbar[j]); BN_free(xhat[j]); 19552b15cb3dSCy Schubert BN_free(s1[j]); 19562b15cb3dSCy Schubert } 19579c2daa00SOllivier Robert return (pkey); 19589c2daa00SOllivier Robert } 19599c2daa00SOllivier Robert 19609c2daa00SOllivier Robert 19619c2daa00SOllivier Robert /* 19622b15cb3dSCy Schubert * Generate X509v3 certificate. 19639c2daa00SOllivier Robert * 19649c2daa00SOllivier Robert * The certificate consists of the version number, serial number, 19659c2daa00SOllivier Robert * validity interval, issuer name, subject name and public key. For a 19669c2daa00SOllivier Robert * self-signed certificate, the issuer name is the same as the subject 19679c2daa00SOllivier Robert * name and these items are signed using the subject private key. The 19689c2daa00SOllivier Robert * validity interval extends from the current time to the same time one 19699c2daa00SOllivier Robert * year hence. For NTP purposes, it is convenient to use the NTP seconds 19709c2daa00SOllivier Robert * of the current time as the serial number. 19719c2daa00SOllivier Robert */ 19729c2daa00SOllivier Robert int 19739c2daa00SOllivier Robert x509 ( 19742b15cb3dSCy Schubert EVP_PKEY *pkey, /* signing key */ 19752b15cb3dSCy Schubert const EVP_MD *md, /* signature/digest scheme */ 19769c2daa00SOllivier Robert char *gqpub, /* identity extension (hex string) */ 19772b15cb3dSCy Schubert const char *exten, /* private cert extension */ 19782b15cb3dSCy Schubert char *name /* subject/issuer name */ 19799c2daa00SOllivier Robert ) 19809c2daa00SOllivier Robert { 19819c2daa00SOllivier Robert X509 *cert; /* X509 certificate */ 19829c2daa00SOllivier Robert X509_NAME *subj; /* distinguished (common) name */ 19839c2daa00SOllivier Robert X509_EXTENSION *ex; /* X509v3 extension */ 19849c2daa00SOllivier Robert FILE *str; /* file handle */ 19859c2daa00SOllivier Robert ASN1_INTEGER *serial; /* serial number */ 19869c2daa00SOllivier Robert const char *id; /* digest/signature scheme name */ 19879c2daa00SOllivier Robert char pathbuf[MAXFILENAME + 1]; 19889c2daa00SOllivier Robert 19899c2daa00SOllivier Robert /* 19909c2daa00SOllivier Robert * Generate X509 self-signed certificate. 19919c2daa00SOllivier Robert * 19929c2daa00SOllivier Robert * Set the certificate serial to the NTP seconds for grins. Set 19932b15cb3dSCy Schubert * the version to 3. Set the initial validity to the current 19942b15cb3dSCy Schubert * time and the finalvalidity one year hence. 19959c2daa00SOllivier Robert */ 1996f391d6bcSXin LI id = OBJ_nid2sn(EVP_MD_pkey_type(md)); 19972b15cb3dSCy Schubert fprintf(stderr, "Generating new certificate %s %s\n", name, id); 19989c2daa00SOllivier Robert cert = X509_new(); 19999c2daa00SOllivier Robert X509_set_version(cert, 2L); 20009c2daa00SOllivier Robert serial = ASN1_INTEGER_new(); 20012b15cb3dSCy Schubert ASN1_INTEGER_set(serial, (long)epoch + JAN_1970); 20029c2daa00SOllivier Robert X509_set_serialNumber(cert, serial); 20039c2daa00SOllivier Robert ASN1_INTEGER_free(serial); 2004f0574f5cSXin LI X509_time_adj(X509_getm_notBefore(cert), 0L, &epoch); 2005f0574f5cSXin LI X509_time_adj(X509_getm_notAfter(cert), lifetime * SECSPERDAY, &epoch); 20069c2daa00SOllivier Robert subj = X509_get_subject_name(cert); 20079c2daa00SOllivier Robert X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, 20083311ff84SXin LI (u_char *)name, -1, -1, 0); 20099c2daa00SOllivier Robert subj = X509_get_issuer_name(cert); 20109c2daa00SOllivier Robert X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, 20113311ff84SXin LI (u_char *)name, -1, -1, 0); 20129c2daa00SOllivier Robert if (!X509_set_pubkey(cert, pkey)) { 20132b15cb3dSCy Schubert fprintf(stderr, "Assign certificate signing key fails\n%s\n", 20149c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20159c2daa00SOllivier Robert X509_free(cert); 20169c2daa00SOllivier Robert return (0); 20179c2daa00SOllivier Robert } 20189c2daa00SOllivier Robert 20199c2daa00SOllivier Robert /* 20209c2daa00SOllivier Robert * Add X509v3 extensions if present. These represent the minimum 20219c2daa00SOllivier Robert * set defined in RFC3280 less the certificate_policy extension, 20229c2daa00SOllivier Robert * which is seriously obfuscated in OpenSSL. 20239c2daa00SOllivier Robert */ 20249c2daa00SOllivier Robert /* 20259c2daa00SOllivier Robert * The basic_constraints extension CA:TRUE allows servers to 20269c2daa00SOllivier Robert * sign client certficitates. 20279c2daa00SOllivier Robert */ 20289c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_basic_constraints, 20299c2daa00SOllivier Robert BASIC_CONSTRAINTS); 20309c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, 20312b15cb3dSCy Schubert _UC(BASIC_CONSTRAINTS)); 20329c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20339c2daa00SOllivier Robert fprintf(stderr, "Add extension field fails\n%s\n", 20349c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20359c2daa00SOllivier Robert return (0); 20369c2daa00SOllivier Robert } 20379c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20389c2daa00SOllivier Robert 20399c2daa00SOllivier Robert /* 20409c2daa00SOllivier Robert * The key_usage extension designates the purposes the key can 20419c2daa00SOllivier Robert * be used for. 20429c2daa00SOllivier Robert */ 20439c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_key_usage, KEY_USAGE); 20442b15cb3dSCy Schubert ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, _UC(KEY_USAGE)); 20459c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20469c2daa00SOllivier Robert fprintf(stderr, "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 * The subject_key_identifier is used for the GQ public key. 20539c2daa00SOllivier Robert * This should not be controversial. 20549c2daa00SOllivier Robert */ 20559c2daa00SOllivier Robert if (gqpub != NULL) { 20569c2daa00SOllivier Robert fprintf(stderr, "%s\n", LN_subject_key_identifier); 20579c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, 20589c2daa00SOllivier Robert NID_subject_key_identifier, gqpub); 20599c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20609c2daa00SOllivier Robert fprintf(stderr, 20619c2daa00SOllivier Robert "Add extension field fails\n%s\n", 20629c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20639c2daa00SOllivier Robert return (0); 20649c2daa00SOllivier Robert } 20659c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20669c2daa00SOllivier Robert } 20679c2daa00SOllivier Robert 20689c2daa00SOllivier Robert /* 20699c2daa00SOllivier Robert * The extended key usage extension is used for special purpose 20709c2daa00SOllivier Robert * here. The semantics probably do not conform to the designer's 20719c2daa00SOllivier Robert * intent and will likely change in future. 20729c2daa00SOllivier Robert * 20739c2daa00SOllivier Robert * "trustRoot" designates a root authority 20749c2daa00SOllivier Robert * "private" designates a private certificate 20759c2daa00SOllivier Robert */ 20769c2daa00SOllivier Robert if (exten != NULL) { 20779c2daa00SOllivier Robert fprintf(stderr, "%s: %s\n", LN_ext_key_usage, exten); 20789c2daa00SOllivier Robert ex = X509V3_EXT_conf_nid(NULL, NULL, 20792b15cb3dSCy Schubert NID_ext_key_usage, _UC(exten)); 20809c2daa00SOllivier Robert if (!X509_add_ext(cert, ex, -1)) { 20819c2daa00SOllivier Robert fprintf(stderr, 20829c2daa00SOllivier Robert "Add extension field fails\n%s\n", 20839c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20849c2daa00SOllivier Robert return (0); 20859c2daa00SOllivier Robert } 20869c2daa00SOllivier Robert X509_EXTENSION_free(ex); 20879c2daa00SOllivier Robert } 20889c2daa00SOllivier Robert 20899c2daa00SOllivier Robert /* 20909c2daa00SOllivier Robert * Sign and verify. 20919c2daa00SOllivier Robert */ 20929c2daa00SOllivier Robert X509_sign(cert, pkey, md); 20932b15cb3dSCy Schubert if (X509_verify(cert, pkey) <= 0) { 20949c2daa00SOllivier Robert fprintf(stderr, "Verify %s certificate fails\n%s\n", id, 20959c2daa00SOllivier Robert ERR_error_string(ERR_get_error(), NULL)); 20969c2daa00SOllivier Robert X509_free(cert); 20979c2daa00SOllivier Robert return (0); 20989c2daa00SOllivier Robert } 20999c2daa00SOllivier Robert 21009c2daa00SOllivier Robert /* 21019c2daa00SOllivier Robert * Write the certificate encoded in PEM. 21029c2daa00SOllivier Robert */ 21032b15cb3dSCy Schubert snprintf(pathbuf, sizeof(pathbuf), "%scert", id); 21042b15cb3dSCy Schubert str = fheader(pathbuf, "cert", hostname); 21059c2daa00SOllivier Robert PEM_write_X509(str, cert); 21069c2daa00SOllivier Robert fclose(str); 21079c2daa00SOllivier Robert if (debug) 21082b15cb3dSCy Schubert X509_print_fp(stderr, cert); 21099c2daa00SOllivier Robert X509_free(cert); 21109c2daa00SOllivier Robert return (1); 21119c2daa00SOllivier Robert } 21129c2daa00SOllivier Robert 21132b15cb3dSCy Schubert #if 0 /* asn2ntp is used only with commercial certificates */ 21149c2daa00SOllivier Robert /* 21159c2daa00SOllivier Robert * asn2ntp - convert ASN1_TIME time structure to NTP time 21169c2daa00SOllivier Robert */ 21179c2daa00SOllivier Robert u_long 21189c2daa00SOllivier Robert asn2ntp ( 21199c2daa00SOllivier Robert ASN1_TIME *asn1time /* pointer to ASN1_TIME structure */ 21209c2daa00SOllivier Robert ) 21219c2daa00SOllivier Robert { 21229c2daa00SOllivier Robert char *v; /* pointer to ASN1_TIME string */ 21239c2daa00SOllivier Robert struct tm tm; /* time decode structure time */ 21249c2daa00SOllivier Robert 21259c2daa00SOllivier Robert /* 21269c2daa00SOllivier Robert * Extract time string YYMMDDHHMMSSZ from ASN.1 time structure. 21279c2daa00SOllivier Robert * Note that the YY, MM, DD fields start with one, the HH, MM, 21289c2daa00SOllivier Robert * SS fiels start with zero and the Z character should be 'Z' 21299c2daa00SOllivier Robert * for UTC. Also note that years less than 50 map to years 21309c2daa00SOllivier Robert * greater than 100. Dontcha love ASN.1? 21319c2daa00SOllivier Robert */ 21329c2daa00SOllivier Robert if (asn1time->length > 13) 21339c2daa00SOllivier Robert return (-1); 21349c2daa00SOllivier Robert v = (char *)asn1time->data; 21359c2daa00SOllivier Robert tm.tm_year = (v[0] - '0') * 10 + v[1] - '0'; 21369c2daa00SOllivier Robert if (tm.tm_year < 50) 21379c2daa00SOllivier Robert tm.tm_year += 100; 21389c2daa00SOllivier Robert tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1; 21399c2daa00SOllivier Robert tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0'; 21409c2daa00SOllivier Robert tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0'; 21419c2daa00SOllivier Robert tm.tm_min = (v[8] - '0') * 10 + v[9] - '0'; 21429c2daa00SOllivier Robert tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0'; 21439c2daa00SOllivier Robert tm.tm_wday = 0; 21449c2daa00SOllivier Robert tm.tm_yday = 0; 21459c2daa00SOllivier Robert tm.tm_isdst = 0; 21469c2daa00SOllivier Robert return (mktime(&tm) + JAN_1970); 21479c2daa00SOllivier Robert } 21489c2daa00SOllivier Robert #endif 21499c2daa00SOllivier Robert 21509c2daa00SOllivier Robert /* 21519c2daa00SOllivier Robert * Callback routine 21529c2daa00SOllivier Robert */ 21539c2daa00SOllivier Robert void 21549c2daa00SOllivier Robert cb ( 21559c2daa00SOllivier Robert int n1, /* arg 1 */ 21569c2daa00SOllivier Robert int n2, /* arg 2 */ 21579c2daa00SOllivier Robert void *chr /* arg 3 */ 21589c2daa00SOllivier Robert ) 21599c2daa00SOllivier Robert { 21609c2daa00SOllivier Robert switch (n1) { 21619c2daa00SOllivier Robert case 0: 21629c2daa00SOllivier Robert d0++; 21639c2daa00SOllivier Robert fprintf(stderr, "%s %d %d %lu\r", (char *)chr, n1, n2, 21649c2daa00SOllivier Robert d0); 21659c2daa00SOllivier Robert break; 21669c2daa00SOllivier Robert case 1: 21679c2daa00SOllivier Robert d1++; 21689c2daa00SOllivier Robert fprintf(stderr, "%s\t\t%d %d %lu\r", (char *)chr, n1, 21699c2daa00SOllivier Robert n2, d1); 21709c2daa00SOllivier Robert break; 21719c2daa00SOllivier Robert case 2: 21729c2daa00SOllivier Robert d2++; 21739c2daa00SOllivier Robert fprintf(stderr, "%s\t\t\t\t%d %d %lu\r", (char *)chr, 21749c2daa00SOllivier Robert n1, n2, d2); 21759c2daa00SOllivier Robert break; 21769c2daa00SOllivier Robert case 3: 21779c2daa00SOllivier Robert d3++; 21789c2daa00SOllivier Robert fprintf(stderr, "%s\t\t\t\t\t\t%d %d %lu\r", 21799c2daa00SOllivier Robert (char *)chr, n1, n2, d3); 21809c2daa00SOllivier Robert break; 21819c2daa00SOllivier Robert } 21829c2daa00SOllivier Robert } 21839c2daa00SOllivier Robert 21849c2daa00SOllivier Robert 21859c2daa00SOllivier Robert /* 21869c2daa00SOllivier Robert * Generate key 21879c2daa00SOllivier Robert */ 21889c2daa00SOllivier Robert EVP_PKEY * /* public/private key pair */ 21899c2daa00SOllivier Robert genkey( 21902b15cb3dSCy Schubert const char *type, /* key type (RSA or DSA) */ 21912b15cb3dSCy Schubert const char *id /* file name id */ 21929c2daa00SOllivier Robert ) 21939c2daa00SOllivier Robert { 21949c2daa00SOllivier Robert if (type == NULL) 21959c2daa00SOllivier Robert return (NULL); 21969c2daa00SOllivier Robert if (strcmp(type, "RSA") == 0) 21979c2daa00SOllivier Robert return (gen_rsa(id)); 21989c2daa00SOllivier Robert 21999c2daa00SOllivier Robert else if (strcmp(type, "DSA") == 0) 22009c2daa00SOllivier Robert return (gen_dsa(id)); 22019c2daa00SOllivier Robert 22029c2daa00SOllivier Robert fprintf(stderr, "Invalid %s key type %s\n", id, type); 22039c2daa00SOllivier Robert return (NULL); 22049c2daa00SOllivier Robert } 2205f391d6bcSXin LI 2206f391d6bcSXin LI static RSA* 2207f391d6bcSXin LI genRsaKeyPair( 2208f391d6bcSXin LI int bits, 2209f391d6bcSXin LI char * what 2210f391d6bcSXin LI ) 2211f391d6bcSXin LI { 2212f391d6bcSXin LI RSA * rsa = RSA_new(); 2213f391d6bcSXin LI BN_GENCB * gcb = BN_GENCB_new(); 2214f391d6bcSXin LI BIGNUM * bne = BN_new(); 2215f391d6bcSXin LI 2216f391d6bcSXin LI if (gcb) 2217f391d6bcSXin LI BN_GENCB_set_old(gcb, cb, what); 2218f391d6bcSXin LI if (bne) 2219f391d6bcSXin LI BN_set_word(bne, 65537); 2220f391d6bcSXin LI if (!(rsa && gcb && bne && RSA_generate_key_ex( 2221f391d6bcSXin LI rsa, bits, bne, gcb))) 2222f391d6bcSXin LI { 2223f391d6bcSXin LI RSA_free(rsa); 2224f391d6bcSXin LI rsa = NULL; 2225f391d6bcSXin LI } 2226f391d6bcSXin LI BN_GENCB_free(gcb); 2227f391d6bcSXin LI BN_free(bne); 2228f391d6bcSXin LI return rsa; 2229f391d6bcSXin LI } 2230f391d6bcSXin LI 2231f391d6bcSXin LI static DSA* 2232f391d6bcSXin LI genDsaParams( 2233f391d6bcSXin LI int bits, 2234f391d6bcSXin LI char * what 2235f391d6bcSXin LI ) 2236f391d6bcSXin LI { 2237f391d6bcSXin LI 2238f391d6bcSXin LI DSA * dsa = DSA_new(); 2239f391d6bcSXin LI BN_GENCB * gcb = BN_GENCB_new(); 2240f391d6bcSXin LI u_char seed[20]; 2241f391d6bcSXin LI 2242f391d6bcSXin LI if (gcb) 2243f391d6bcSXin LI BN_GENCB_set_old(gcb, cb, what); 2244f391d6bcSXin LI RAND_bytes(seed, sizeof(seed)); 2245f391d6bcSXin LI if (!(dsa && gcb && DSA_generate_parameters_ex( 2246f391d6bcSXin LI dsa, bits, seed, sizeof(seed), NULL, NULL, gcb))) 2247f391d6bcSXin LI { 2248f391d6bcSXin LI DSA_free(dsa); 2249f391d6bcSXin LI dsa = NULL; 2250f391d6bcSXin LI } 2251f391d6bcSXin LI BN_GENCB_free(gcb); 2252f391d6bcSXin LI return dsa; 2253f391d6bcSXin LI } 2254f391d6bcSXin LI 22552b15cb3dSCy Schubert #endif /* AUTOKEY */ 22569c2daa00SOllivier Robert 22579c2daa00SOllivier Robert 22589c2daa00SOllivier Robert /* 22592b15cb3dSCy Schubert * Generate file header and link 22609c2daa00SOllivier Robert */ 22619c2daa00SOllivier Robert FILE * 22629c2daa00SOllivier Robert fheader ( 22632b15cb3dSCy Schubert const char *file, /* file name id */ 22642b15cb3dSCy Schubert const char *ulink, /* linkname */ 22652b15cb3dSCy Schubert const char *owner /* owner name */ 22669c2daa00SOllivier Robert ) 22679c2daa00SOllivier Robert { 22689c2daa00SOllivier Robert FILE *str; /* file handle */ 22692b15cb3dSCy Schubert char linkname[MAXFILENAME]; /* link name */ 22702b15cb3dSCy Schubert int temp; 2271a25439b6SCy Schubert #ifdef HAVE_UMASK 2272a25439b6SCy Schubert mode_t orig_umask; 2273a25439b6SCy Schubert #endif 22749c2daa00SOllivier Robert 22752b15cb3dSCy Schubert snprintf(filename, sizeof(filename), "ntpkey_%s_%s.%u", file, 22762b15cb3dSCy Schubert owner, fstamp); 2277a25439b6SCy Schubert #ifdef HAVE_UMASK 2278a25439b6SCy Schubert orig_umask = umask( S_IWGRP | S_IRWXO ); 2279a25439b6SCy Schubert str = fopen(filename, "w"); 2280a25439b6SCy Schubert (void) umask(orig_umask); 2281a25439b6SCy Schubert #else 2282a25439b6SCy Schubert str = fopen(filename, "w"); 2283a25439b6SCy Schubert #endif 2284a25439b6SCy Schubert if (str == NULL) { 22859c2daa00SOllivier Robert perror("Write"); 22869c2daa00SOllivier Robert exit (-1); 22879c2daa00SOllivier Robert } 2288a25439b6SCy Schubert if (strcmp(ulink, "md5") == 0) { 2289a25439b6SCy Schubert strcpy(linkname,"ntp.keys"); 2290a25439b6SCy Schubert } else { 22912b15cb3dSCy Schubert snprintf(linkname, sizeof(linkname), "ntpkey_%s_%s", ulink, 22922b15cb3dSCy Schubert hostname); 2293a25439b6SCy Schubert } 22942b15cb3dSCy Schubert (void)remove(linkname); /* The symlink() line below matters */ 22959c2daa00SOllivier Robert temp = symlink(filename, linkname); 22969c2daa00SOllivier Robert if (temp < 0) 22972b15cb3dSCy Schubert perror(file); 22982b15cb3dSCy Schubert fprintf(stderr, "Generating new %s file and link\n", ulink); 22999c2daa00SOllivier Robert fprintf(stderr, "%s->%s\n", linkname, filename); 23002b15cb3dSCy Schubert fprintf(str, "# %s\n# %s\n", filename, ctime(&epoch)); 23012b15cb3dSCy Schubert return (str); 23029c2daa00SOllivier Robert } 2303