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