1132451Sroberto/* 2132451Sroberto * Program to generate cryptographic keys for NTP clients and servers 3132451Sroberto * 4132451Sroberto * This program generates files "ntpkey_<type>_<hostname>.<filestamp>", 5132451Sroberto * where <type> is the file type, <hostname> is the generating host and 6132451Sroberto * <filestamp> is the NTP seconds in decimal format. The NTP programs 7132451Sroberto * expect generic names such as "ntpkey_<type>_whimsy.udel.edu" with the 8132451Sroberto * association maintained by soft links. 9132451Sroberto * 10132451Sroberto * Files are prefixed with a header giving the name and date of creation 11132451Sroberto * followed by a type-specific descriptive label and PEM-encoded data 12132451Sroberto * string compatible with programs of the OpenSSL library. 13132451Sroberto * 14132451Sroberto * Note that private keys can be password encrypted as per OpenSSL 15132451Sroberto * conventions. 16132451Sroberto * 17132451Sroberto * The file types include 18132451Sroberto * 19132451Sroberto * ntpkey_MD5key_<hostname>.<filestamp> 20132451Sroberto * MD5 (128-bit) keys used to compute message digests in symmetric 21132451Sroberto * key cryptography 22132451Sroberto * 23132451Sroberto * ntpkey_RSAkey_<hostname>.<filestamp> 24132451Sroberto * ntpkey_host_<hostname> (RSA) link 25132451Sroberto * RSA private/public host key pair used for public key signatures 26132451Sroberto * and data encryption 27132451Sroberto * 28132451Sroberto * ntpkey_DSAkey_<hostname>.<filestamp> 29132451Sroberto * ntpkey_sign_<hostname> (RSA or DSA) link 30132451Sroberto * DSA private/public sign key pair used for public key signatures, 31132451Sroberto * but not data encryption 32132451Sroberto * 33132451Sroberto * ntpkey_IFFpar_<hostname>.<filestamp> 34132451Sroberto * ntpkey_iff_<hostname> (IFF server/client) link 35132451Sroberto * ntpkey_iffkey_<hostname> (IFF client) link 36132451Sroberto * Schnorr (IFF) server/client identity parameters 37132451Sroberto * 38132451Sroberto * ntpkey_IFFkey_<hostname>.<filestamp> 39132451Sroberto * Schnorr (IFF) client identity parameters 40132451Sroberto * 41132451Sroberto * ntpkey_GQpar_<hostname>.<filestamp>, 42132451Sroberto * ntpkey_gq_<hostname> (GQ) link 43132451Sroberto * Guillou-Quisquater (GQ) identity parameters 44132451Sroberto * 45132451Sroberto * ntpkey_MVpar_<hostname>.<filestamp>, 46132451Sroberto * Mu-Varadharajan (MV) server identity parameters 47132451Sroberto * 48132451Sroberto * ntpkey_MVkeyX_<hostname>.<filestamp>, 49132451Sroberto * ntpkey_mv_<hostname> (MV server) link 50132451Sroberto * ntpkey_mvkey_<hostname> (MV client) link 51132451Sroberto * Mu-Varadharajan (MV) client identity parameters 52132451Sroberto * 53132451Sroberto * ntpkey_XXXcert_<hostname>.<filestamp> 54132451Sroberto * ntpkey_cert_<hostname> (RSA or DSA) link 55132451Sroberto * X509v3 certificate using RSA or DSA public keys and signatures. 56132451Sroberto * XXX is a code identifying the message digest and signature 57132451Sroberto * encryption algorithm 58132451Sroberto * 59132451Sroberto * Available digest/signature schemes 60132451Sroberto * 61132451Sroberto * RSA: RSA-MD2, RSA-MD5, RSA-SHA, RSA-SHA1, RSA-MDC2, EVP-RIPEMD160 62132451Sroberto * DSA: DSA-SHA, DSA-SHA1 63132451Sroberto * 64132451Sroberto * Note: Once in a while because of some statistical fluke this program 65132451Sroberto * fails to generate and verify some cryptographic data, as indicated by 66132451Sroberto * exit status -1. In this case simply run the program again. If the 67132451Sroberto * program does complete with return code 0, the data are correct as 68132451Sroberto * verified. 69132451Sroberto * 70132451Sroberto * These cryptographic routines are characterized by the prime modulus 71132451Sroberto * size in bits. The default value of 512 bits is a compromise between 72132451Sroberto * cryptographic strength and computing time and is ordinarily 73132451Sroberto * considered adequate for this application. The routines have been 74132451Sroberto * tested with sizes of 256, 512, 1024 and 2048 bits. Not all message 75132451Sroberto * digest and signature encryption schemes work with sizes less than 512 76132451Sroberto * bits. The computing time for sizes greater than 2048 bits is 77132451Sroberto * prohibitive on all but the fastest processors. An UltraSPARC Blade 78132451Sroberto * 1000 took something over nine minutes to generate and verify the 79132451Sroberto * values with size 2048. An old SPARC IPC would take a week. 80132451Sroberto * 81132451Sroberto * The OpenSSL library used by this program expects a random seed file. 82132451Sroberto * As described in the OpenSSL documentation, the file name defaults to 83132451Sroberto * first the RANDFILE environment variable in the user's home directory 84132451Sroberto * and then .rnd in the user's home directory. 85132451Sroberto */ 86132451Sroberto#ifdef HAVE_CONFIG_H 87132451Sroberto# include <config.h> 88132451Sroberto#endif 89132451Sroberto#include <string.h> 90132451Sroberto#include <stdio.h> 91132451Sroberto#include <stdlib.h> 92132451Sroberto#include <unistd.h> 93132451Sroberto#include <sys/stat.h> 94132451Sroberto#include <sys/time.h> 95132451Sroberto#if HAVE_SYS_TYPES_H 96132451Sroberto# include <sys/types.h> 97132451Sroberto#endif 98132451Sroberto#include "ntp_types.h" 99182007Sroberto#include "ntp_random.h" 100132451Sroberto#include "l_stdlib.h" 101132451Sroberto 102182007Sroberto#include "ntp-keygen-opts.h" 103182007Sroberto 104132451Sroberto#ifdef SYS_WINNT 105132451Srobertoextern int ntp_getopt P((int, char **, const char *)); 106132451Sroberto#define getopt ntp_getopt 107132451Sroberto#define optarg ntp_optarg 108132451Sroberto#endif 109132451Sroberto 110132451Sroberto#ifdef OPENSSL 111132451Sroberto#include "openssl/bn.h" 112132451Sroberto#include "openssl/evp.h" 113132451Sroberto#include "openssl/err.h" 114132451Sroberto#include "openssl/rand.h" 115132451Sroberto#include "openssl/pem.h" 116132451Sroberto#include "openssl/x509v3.h" 117132451Sroberto#include <openssl/objects.h> 118132451Sroberto#endif /* OPENSSL */ 119132451Sroberto 120132451Sroberto/* 121132451Sroberto * Cryptodefines 122132451Sroberto */ 123132451Sroberto#define MD5KEYS 16 /* number of MD5 keys generated */ 124132451Sroberto#define JAN_1970 ULONG_CONST(2208988800) /* NTP seconds */ 125132451Sroberto#define YEAR ((long)60*60*24*365) /* one year in seconds */ 126132451Sroberto#define MAXFILENAME 256 /* max file name length */ 127132451Sroberto#define MAXHOSTNAME 256 /* max host name length */ 128132451Sroberto#ifdef OPENSSL 129132451Sroberto#define PLEN 512 /* default prime modulus size (bits) */ 130132451Sroberto 131132451Sroberto/* 132132451Sroberto * Strings used in X509v3 extension fields 133132451Sroberto */ 134132451Sroberto#define KEY_USAGE "digitalSignature,keyCertSign" 135132451Sroberto#define BASIC_CONSTRAINTS "critical,CA:TRUE" 136132451Sroberto#define EXT_KEY_PRIVATE "private" 137132451Sroberto#define EXT_KEY_TRUST "trustRoot" 138132451Sroberto#endif /* OPENSSL */ 139132451Sroberto 140132451Sroberto/* 141132451Sroberto * Prototypes 142132451Sroberto */ 143132451SrobertoFILE *fheader P((const char *, const char *)); 144132451Srobertovoid fslink P((const char *, const char *)); 145132451Srobertoint gen_md5 P((char *)); 146132451Sroberto#ifdef OPENSSL 147132451SrobertoEVP_PKEY *gen_rsa P((char *)); 148132451SrobertoEVP_PKEY *gen_dsa P((char *)); 149132451SrobertoEVP_PKEY *gen_iff P((char *)); 150132451SrobertoEVP_PKEY *gen_gqpar P((char *)); 151132451SrobertoEVP_PKEY *gen_gqkey P((char *, EVP_PKEY *)); 152132451SrobertoEVP_PKEY *gen_mv P((char *)); 153132451Srobertoint x509 P((EVP_PKEY *, const EVP_MD *, char *, char *)); 154132451Srobertovoid cb P((int, int, void *)); 155132451SrobertoEVP_PKEY *genkey P((char *, char *)); 156132451Srobertou_long asn2ntp P((ASN1_TIME *)); 157132451Sroberto#endif /* OPENSSL */ 158132451Sroberto 159132451Sroberto/* 160132451Sroberto * Program variables 161132451Sroberto */ 162132451Srobertoextern char *optarg; /* command line argument */ 163132451Srobertoint debug = 0; /* debug, not de bug */ 164132451Srobertoint rval; /* return status */ 165132536Sroberto#ifdef OPENSSL 166132451Srobertou_int modulus = PLEN; /* prime modulus size (bits) */ 167132536Sroberto#endif 168132451Srobertoint nkeys = 0; /* MV keys */ 169132451Srobertotime_t epoch; /* Unix epoch (seconds) since 1970 */ 170132451Srobertochar *hostname; /* host name (subject name) */ 171132451Srobertochar *trustname; /* trusted host name (issuer name) */ 172132451Srobertochar filename[MAXFILENAME + 1]; /* file name */ 173132451Srobertochar *passwd1 = NULL; /* input private key password */ 174132451Srobertochar *passwd2 = NULL; /* output private key password */ 175132451Sroberto#ifdef OPENSSL 176132451Srobertolong d0, d1, d2, d3; /* callback counters */ 177132451Sroberto#endif /* OPENSSL */ 178132451Sroberto 179132451Sroberto#ifdef SYS_WINNT 180132451SrobertoBOOL init_randfile(); 181132451Sroberto 182132451Sroberto/* 183132451Sroberto * Don't try to follow symbolic links 184132451Sroberto */ 185132451Srobertoint 186132451Srobertoreadlink(char * link, char * file, int len) { 187132451Sroberto return (-1); 188132451Sroberto} 189132451Sroberto/* 190132451Sroberto * Don't try to create a symbolic link for now. 191132451Sroberto * Just move the file to the name you need. 192132451Sroberto */ 193132451Srobertoint 194132451Srobertosymlink(char *filename, char *linkname) { 195132451Sroberto DeleteFile(linkname); 196132451Sroberto MoveFile(filename, linkname); 197132451Sroberto return 0; 198132451Sroberto} 199132451Srobertovoid 200132451SrobertoInitWin32Sockets() { 201132451Sroberto WORD wVersionRequested; 202132451Sroberto WSADATA wsaData; 203132451Sroberto wVersionRequested = MAKEWORD(2,0); 204132451Sroberto if (WSAStartup(wVersionRequested, &wsaData)) 205132451Sroberto { 206132451Sroberto fprintf(stderr, "No useable winsock.dll"); 207132451Sroberto exit(1); 208132451Sroberto } 209132451Sroberto} 210132451Sroberto#endif /* SYS_WINNT */ 211132451Sroberto 212132451Sroberto/* 213132451Sroberto * Main program 214132451Sroberto */ 215132451Srobertoint 216132451Srobertomain( 217132451Sroberto int argc, /* command line options */ 218132451Sroberto char **argv 219132451Sroberto ) 220132451Sroberto{ 221132451Sroberto struct timeval tv; /* initialization vector */ 222182007Sroberto int md5key = 0; /* generate MD5 keys */ 223132451Sroberto#ifdef OPENSSL 224132451Sroberto X509 *cert = NULL; /* X509 certificate */ 225132451Sroberto EVP_PKEY *pkey_host = NULL; /* host key */ 226132451Sroberto EVP_PKEY *pkey_sign = NULL; /* sign key */ 227132451Sroberto EVP_PKEY *pkey_iff = NULL; /* IFF parameters */ 228132451Sroberto EVP_PKEY *pkey_gq = NULL; /* GQ parameters */ 229132451Sroberto EVP_PKEY *pkey_mv = NULL; /* MV parameters */ 230132451Sroberto int hostkey = 0; /* generate RSA keys */ 231132451Sroberto int iffkey = 0; /* generate IFF parameters */ 232132451Sroberto int gqpar = 0; /* generate GQ parameters */ 233132451Sroberto int gqkey = 0; /* update GQ keys */ 234132451Sroberto int mvpar = 0; /* generate MV parameters */ 235132451Sroberto int mvkey = 0; /* update MV keys */ 236132451Sroberto char *sign = NULL; /* sign key */ 237132451Sroberto EVP_PKEY *pkey = NULL; /* temp key */ 238132451Sroberto const EVP_MD *ectx; /* EVP digest */ 239132451Sroberto char pathbuf[MAXFILENAME + 1]; 240132451Sroberto const char *scheme = NULL; /* digest/signature scheme */ 241132451Sroberto char *exten = NULL; /* private extension */ 242132451Sroberto char *grpkey = NULL; /* identity extension */ 243132451Sroberto int nid; /* X509 digest/signature scheme */ 244132451Sroberto FILE *fstr = NULL; /* file handle */ 245182007Sroberto u_int temp; 246182007Sroberto#define iffsw HAVE_OPT(ID_KEY) 247132451Sroberto#endif /* OPENSSL */ 248132536Sroberto char hostbuf[MAXHOSTNAME + 1]; 249132451Sroberto 250132451Sroberto#ifdef SYS_WINNT 251132451Sroberto /* Initialize before OpenSSL checks */ 252132451Sroberto InitWin32Sockets(); 253132451Sroberto if(!init_randfile()) 254132451Sroberto fprintf(stderr, "Unable to initialize .rnd file\n"); 255132451Sroberto#endif 256132451Sroberto 257132451Sroberto#ifdef OPENSSL 258182007Sroberto /* 259182007Sroberto * OpenSSL version numbers: MNNFFPPS: major minor fix patch status 260182007Sroberto * We match major, minor, fix and status (not patch) 261182007Sroberto */ 262182007Sroberto if ((SSLeay() ^ OPENSSL_VERSION_NUMBER) & ~0xff0L) { 263132451Sroberto fprintf(stderr, 264132451Sroberto "OpenSSL version mismatch. Built against %lx, you have %lx\n", 265132451Sroberto OPENSSL_VERSION_NUMBER, SSLeay()); 266132451Sroberto return (-1); 267132451Sroberto 268132451Sroberto } else { 269132451Sroberto fprintf(stderr, 270132451Sroberto "Using OpenSSL version %lx\n", SSLeay()); 271132451Sroberto } 272132451Sroberto#endif /* OPENSSL */ 273132451Sroberto 274132451Sroberto /* 275132451Sroberto * Process options, initialize host name and timestamp. 276132451Sroberto */ 277132451Sroberto gethostname(hostbuf, MAXHOSTNAME); 278132451Sroberto hostname = hostbuf; 279132536Sroberto#ifdef OPENSSL 280132451Sroberto trustname = hostbuf; 281132451Sroberto passwd1 = hostbuf; 282132536Sroberto#endif 283132451Sroberto#ifndef SYS_WINNT 284132451Sroberto gettimeofday(&tv, 0); 285132451Sroberto#else 286132451Sroberto gettimeofday(&tv); 287132451Sroberto#endif 288132451Sroberto epoch = tv.tv_sec; 289132451Sroberto rval = 0; 290132451Sroberto 291182007Sroberto { 292182007Sroberto int optct = optionProcess(&ntp_keygenOptions, argc, argv); 293182007Sroberto argc -= optct; 294182007Sroberto argv += optct; 295182007Sroberto } 296182007Sroberto 297132536Sroberto#ifdef OPENSSL 298182007Sroberto if (HAVE_OPT( CERTIFICATE )) 299182007Sroberto scheme = OPT_ARG( CERTIFICATE ); 300132536Sroberto#endif 301132451Sroberto 302182007Sroberto debug = DESC(DEBUG_LEVEL).optOccCt; 303132451Sroberto 304132536Sroberto#ifdef OPENSSL 305182007Sroberto if (HAVE_OPT( GQ_PARAMS )) 306182007Sroberto gqpar++; 307132451Sroberto 308182007Sroberto if (HAVE_OPT( GQ_KEYS )) 309182007Sroberto gqkey++; 310132451Sroberto 311182007Sroberto if (HAVE_OPT( HOST_KEY )) 312182007Sroberto hostkey++; 313132451Sroberto 314182007Sroberto if (HAVE_OPT( IFFKEY )) 315182007Sroberto iffkey++; 316132451Sroberto 317182007Sroberto if (HAVE_OPT( ISSUER_NAME )) 318182007Sroberto trustname = OPT_ARG( ISSUER_NAME ); 319132536Sroberto#endif 320132451Sroberto 321182007Sroberto if (HAVE_OPT( MD5KEY )) 322182007Sroberto md5key++; 323132451Sroberto 324132536Sroberto#ifdef OPENSSL 325182007Sroberto if (HAVE_OPT( MODULUS )) 326182007Sroberto modulus = OPT_VALUE_MODULUS; 327132536Sroberto 328182007Sroberto if (HAVE_OPT( PVT_CERT )) 329182007Sroberto exten = EXT_KEY_PRIVATE; 330132451Sroberto 331182007Sroberto if (HAVE_OPT( PVT_PASSWD )) 332182007Sroberto passwd2 = OPT_ARG( PVT_PASSWD ); 333132451Sroberto 334182007Sroberto if (HAVE_OPT( GET_PVT_PASSWD )) 335182007Sroberto passwd1 = OPT_ARG( GET_PVT_PASSWD ); 336132451Sroberto 337182007Sroberto if (HAVE_OPT( SIGN_KEY )) 338182007Sroberto sign = OPT_ARG( SIGN_KEY ); 339132451Sroberto 340182007Sroberto if (HAVE_OPT( SUBJECT_NAME )) 341182007Sroberto hostname = OPT_ARG( SUBJECT_NAME ); 342132536Sroberto 343182007Sroberto if (HAVE_OPT( TRUSTED_CERT )) 344182007Sroberto exten = EXT_KEY_TRUST; 345132451Sroberto 346182007Sroberto if (HAVE_OPT( MV_PARAMS )) { 347182007Sroberto mvpar++; 348182007Sroberto nkeys = OPT_VALUE_MV_PARAMS; 349182007Sroberto } 350132451Sroberto 351182007Sroberto if (HAVE_OPT( MV_KEYS )) { 352182007Sroberto mvkey++; 353182007Sroberto nkeys = OPT_VALUE_MV_KEYS; 354182007Sroberto } 355132536Sroberto#endif 356132451Sroberto 357132451Sroberto if (passwd1 != NULL && passwd2 == NULL) 358132451Sroberto passwd2 = passwd1; 359132451Sroberto#ifdef OPENSSL 360132451Sroberto /* 361132451Sroberto * Seed random number generator and grow weeds. 362132451Sroberto */ 363132451Sroberto ERR_load_crypto_strings(); 364132451Sroberto OpenSSL_add_all_algorithms(); 365132451Sroberto if (RAND_file_name(pathbuf, MAXFILENAME) == NULL) { 366132451Sroberto fprintf(stderr, "RAND_file_name %s\n", 367132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 368132451Sroberto return (-1); 369132451Sroberto } 370132451Sroberto temp = RAND_load_file(pathbuf, -1); 371132451Sroberto if (temp == 0) { 372132451Sroberto fprintf(stderr, 373132451Sroberto "RAND_load_file %s not found or empty\n", pathbuf); 374132451Sroberto return (-1); 375132451Sroberto } 376132451Sroberto fprintf(stderr, 377132451Sroberto "Random seed file %s %u bytes\n", pathbuf, temp); 378132451Sroberto RAND_add(&epoch, sizeof(epoch), 4.0); 379132536Sroberto#endif 380132451Sroberto 381132451Sroberto /* 382132451Sroberto * Generate new parameters and keys as requested. These replace 383132451Sroberto * any values already generated. 384132451Sroberto */ 385132451Sroberto if (md5key) 386132451Sroberto gen_md5("MD5"); 387132536Sroberto#ifdef OPENSSL 388132451Sroberto if (hostkey) 389132451Sroberto pkey_host = genkey("RSA", "host"); 390132451Sroberto if (sign != NULL) 391132451Sroberto pkey_sign = genkey(sign, "sign"); 392132451Sroberto if (iffkey) 393132451Sroberto pkey_iff = gen_iff("iff"); 394132451Sroberto if (gqpar) 395132451Sroberto pkey_gq = gen_gqpar("gq"); 396132451Sroberto if (mvpar) 397132451Sroberto pkey_mv = gen_mv("mv"); 398132451Sroberto 399132451Sroberto /* 400132451Sroberto * If there is no new host key, look for an existing one. If not 401132451Sroberto * found, create it. 402132451Sroberto */ 403182007Sroberto while (pkey_host == NULL && rval == 0 && !HAVE_OPT(ID_KEY)) { 404132451Sroberto sprintf(filename, "ntpkey_host_%s", hostname); 405132451Sroberto if ((fstr = fopen(filename, "r")) != NULL) { 406132451Sroberto pkey_host = PEM_read_PrivateKey(fstr, NULL, 407132451Sroberto NULL, passwd1); 408132451Sroberto fclose(fstr); 409132451Sroberto readlink(filename, filename, sizeof(filename)); 410132451Sroberto if (pkey_host == NULL) { 411132451Sroberto fprintf(stderr, "Host key\n%s\n", 412132451Sroberto ERR_error_string(ERR_get_error(), 413132451Sroberto NULL)); 414132451Sroberto rval = -1; 415132451Sroberto } else { 416132451Sroberto fprintf(stderr, 417132451Sroberto "Using host key %s\n", filename); 418132451Sroberto } 419132451Sroberto break; 420132451Sroberto 421132451Sroberto } else if ((pkey_host = genkey("RSA", "host")) == 422132451Sroberto NULL) { 423132451Sroberto rval = -1; 424132451Sroberto break; 425132451Sroberto } 426132451Sroberto } 427132451Sroberto 428132451Sroberto /* 429132451Sroberto * If there is no new sign key, look for an existing one. If not 430132451Sroberto * found, use the host key instead. 431132451Sroberto */ 432132451Sroberto pkey = pkey_sign; 433182007Sroberto while (pkey_sign == NULL && rval == 0 && !HAVE_OPT(ID_KEY)) { 434132451Sroberto sprintf(filename, "ntpkey_sign_%s", hostname); 435132451Sroberto if ((fstr = fopen(filename, "r")) != NULL) { 436132451Sroberto pkey_sign = PEM_read_PrivateKey(fstr, NULL, 437132451Sroberto NULL, passwd1); 438132451Sroberto fclose(fstr); 439132451Sroberto readlink(filename, filename, sizeof(filename)); 440132451Sroberto if (pkey_sign == NULL) { 441132451Sroberto fprintf(stderr, "Sign key\n%s\n", 442132451Sroberto ERR_error_string(ERR_get_error(), 443132451Sroberto NULL)); 444132451Sroberto rval = -1; 445132451Sroberto } else { 446132451Sroberto fprintf(stderr, "Using sign key %s\n", 447132451Sroberto filename); 448132451Sroberto } 449132451Sroberto break; 450132451Sroberto } else { 451132451Sroberto pkey = pkey_host; 452132451Sroberto fprintf(stderr, "Using host key as sign key\n"); 453132451Sroberto break; 454132451Sroberto } 455132451Sroberto } 456132451Sroberto 457132451Sroberto /* 458132451Sroberto * If there is no new IFF file, look for an existing one. 459132451Sroberto */ 460132451Sroberto if (pkey_iff == NULL && rval == 0) { 461132451Sroberto sprintf(filename, "ntpkey_iff_%s", hostname); 462132451Sroberto if ((fstr = fopen(filename, "r")) != NULL) { 463132451Sroberto pkey_iff = PEM_read_PrivateKey(fstr, NULL, 464132451Sroberto NULL, passwd1); 465132451Sroberto fclose(fstr); 466132451Sroberto readlink(filename, filename, sizeof(filename)); 467132451Sroberto if (pkey_iff == NULL) { 468132451Sroberto fprintf(stderr, "IFF parameters\n%s\n", 469132451Sroberto ERR_error_string(ERR_get_error(), 470132451Sroberto NULL)); 471132451Sroberto rval = -1; 472132451Sroberto } else { 473132451Sroberto fprintf(stderr, 474132451Sroberto "Using IFF parameters %s\n", 475132451Sroberto filename); 476132451Sroberto } 477132451Sroberto } 478132451Sroberto } 479132451Sroberto 480132451Sroberto /* 481132451Sroberto * If there is no new GQ file, look for an existing one. 482132451Sroberto */ 483182007Sroberto if (pkey_gq == NULL && rval == 0 && !HAVE_OPT(ID_KEY)) { 484132451Sroberto sprintf(filename, "ntpkey_gq_%s", hostname); 485132451Sroberto if ((fstr = fopen(filename, "r")) != NULL) { 486132451Sroberto pkey_gq = PEM_read_PrivateKey(fstr, NULL, NULL, 487132451Sroberto passwd1); 488132451Sroberto fclose(fstr); 489132451Sroberto readlink(filename, filename, sizeof(filename)); 490132451Sroberto if (pkey_gq == NULL) { 491132451Sroberto fprintf(stderr, "GQ parameters\n%s\n", 492132451Sroberto ERR_error_string(ERR_get_error(), 493132451Sroberto NULL)); 494132451Sroberto rval = -1; 495132451Sroberto } else { 496132451Sroberto fprintf(stderr, 497132451Sroberto "Using GQ parameters %s\n", 498132451Sroberto filename); 499132451Sroberto } 500132451Sroberto } 501132451Sroberto } 502132451Sroberto 503132451Sroberto /* 504132451Sroberto * If there is a GQ parameter file, create GQ private/public 505132451Sroberto * keys and extract the public key for the certificate. 506132451Sroberto */ 507132451Sroberto if (pkey_gq != NULL && rval == 0) { 508132451Sroberto gen_gqkey("gq", pkey_gq); 509132451Sroberto grpkey = BN_bn2hex(pkey_gq->pkey.rsa->q); 510132451Sroberto } 511132451Sroberto 512132451Sroberto /* 513132451Sroberto * Generate a X509v3 certificate. 514132451Sroberto */ 515182007Sroberto while (scheme == NULL && rval == 0 && !HAVE_OPT(ID_KEY)) { 516132451Sroberto sprintf(filename, "ntpkey_cert_%s", hostname); 517132451Sroberto if ((fstr = fopen(filename, "r")) != NULL) { 518132451Sroberto cert = PEM_read_X509(fstr, NULL, NULL, NULL); 519132451Sroberto fclose(fstr); 520132451Sroberto readlink(filename, filename, sizeof(filename)); 521132451Sroberto if (cert == NULL) { 522132451Sroberto fprintf(stderr, "Cert \n%s\n", 523132451Sroberto ERR_error_string(ERR_get_error(), 524132451Sroberto NULL)); 525132451Sroberto rval = -1; 526132451Sroberto } else { 527132451Sroberto nid = OBJ_obj2nid( 528132451Sroberto cert->cert_info->signature->algorithm); 529132451Sroberto scheme = OBJ_nid2sn(nid); 530132451Sroberto fprintf(stderr, 531132451Sroberto "Using scheme %s from %s\n", scheme, 532132451Sroberto filename); 533132451Sroberto break; 534132451Sroberto } 535132451Sroberto } 536132451Sroberto scheme = "RSA-MD5"; 537132451Sroberto } 538182007Sroberto if (pkey != NULL && rval == 0 && !HAVE_OPT(ID_KEY)) { 539132451Sroberto ectx = EVP_get_digestbyname(scheme); 540132451Sroberto if (ectx == NULL) { 541132451Sroberto fprintf(stderr, 542132451Sroberto "Invalid digest/signature combination %s\n", 543132451Sroberto scheme); 544132451Sroberto rval = -1; 545132451Sroberto } else { 546132451Sroberto x509(pkey, ectx, grpkey, exten); 547132451Sroberto } 548132451Sroberto } 549132451Sroberto 550132451Sroberto /* 551132451Sroberto * Write the IFF client parameters and keys as a DSA private key 552132451Sroberto * encoded in PEM. Note the private key is obscured. 553132451Sroberto */ 554182007Sroberto if (pkey_iff != NULL && rval == 0 && HAVE_OPT(ID_KEY)) { 555132451Sroberto DSA *dsa; 556132451Sroberto char *sptr; 557182007Sroberto char *tld; 558132451Sroberto 559132451Sroberto sptr = strrchr(filename, '.'); 560182007Sroberto tld = malloc(strlen(sptr)); /* we have an extra byte ... */ 561182007Sroberto strcpy(tld, 1+sptr); /* ... see? */ 562132451Sroberto sprintf(filename, "ntpkey_IFFkey_%s.%s", trustname, 563182007Sroberto tld); 564182007Sroberto free(tld); 565132451Sroberto fprintf(stderr, "Writing new IFF key %s\n", filename); 566132451Sroberto fprintf(stdout, "# %s\n# %s", filename, ctime(&epoch)); 567132451Sroberto dsa = pkey_iff->pkey.dsa; 568132451Sroberto BN_copy(dsa->priv_key, BN_value_one()); 569132451Sroberto pkey = EVP_PKEY_new(); 570132451Sroberto EVP_PKEY_assign_DSA(pkey, dsa); 571132451Sroberto PEM_write_PrivateKey(stdout, pkey, passwd2 ? 572132451Sroberto EVP_des_cbc() : NULL, NULL, 0, NULL, passwd2); 573132451Sroberto fclose(stdout); 574132451Sroberto if (debug) 575132451Sroberto DSA_print_fp(stdout, dsa, 0); 576132451Sroberto } 577132451Sroberto 578132451Sroberto /* 579132451Sroberto * Return the marbles. 580132451Sroberto */ 581132451Sroberto if (grpkey != NULL) 582132451Sroberto OPENSSL_free(grpkey); 583132451Sroberto if (pkey_host != NULL) 584132451Sroberto EVP_PKEY_free(pkey_host); 585132451Sroberto if (pkey_sign != NULL) 586132451Sroberto EVP_PKEY_free(pkey_sign); 587132451Sroberto if (pkey_iff != NULL) 588132451Sroberto EVP_PKEY_free(pkey_iff); 589132451Sroberto if (pkey_gq != NULL) 590132451Sroberto EVP_PKEY_free(pkey_gq); 591132451Sroberto if (pkey_mv != NULL) 592132451Sroberto EVP_PKEY_free(pkey_mv); 593132451Sroberto#endif /* OPENSSL */ 594132451Sroberto return (rval); 595132451Sroberto} 596132451Sroberto 597132451Sroberto 598132451Sroberto#if 0 599132451Sroberto/* 600132451Sroberto * Generate random MD5 key with password. 601132451Sroberto */ 602132451Srobertoint 603132451Srobertogen_md5( 604132451Sroberto char *id /* file name id */ 605132451Sroberto ) 606132451Sroberto{ 607132451Sroberto BIGNUM *key; 608132451Sroberto BIGNUM *keyid; 609132451Sroberto FILE *str; 610132451Sroberto u_char bin[16]; 611132451Sroberto 612132451Sroberto fprintf(stderr, "Generating MD5 keys...\n"); 613132451Sroberto str = fheader("MD5key", hostname); 614132451Sroberto keyid = BN_new(); key = BN_new(); 615132451Sroberto BN_rand(keyid, 16, -1, 0); 616132451Sroberto BN_rand(key, 128, -1, 0); 617132451Sroberto BN_bn2bin(key, bin); 618132451Sroberto PEM_write_fp(str, MD5, NULL, bin); 619132451Sroberto fclose(str); 620132451Sroberto fslink(id, hostname); 621132451Sroberto return (1); 622132451Sroberto} 623132451Sroberto 624132451Sroberto 625132451Sroberto#else 626132451Sroberto/* 627132451Sroberto * Generate semi-random MD5 keys compatible with NTPv3 and NTPv4 628132451Sroberto */ 629132451Srobertoint 630132451Srobertogen_md5( 631132451Sroberto char *id /* file name id */ 632132451Sroberto ) 633132451Sroberto{ 634132451Sroberto u_char md5key[16]; /* MD5 key */ 635132451Sroberto FILE *str; 636132451Sroberto u_int temp = 0; /* Initialize to prevent warnings during compile */ 637132451Sroberto int i, j; 638132451Sroberto 639132451Sroberto fprintf(stderr, "Generating MD5 keys...\n"); 640132451Sroberto str = fheader("MD5key", hostname); 641182007Sroberto ntp_srandom(epoch); 642132451Sroberto for (i = 1; i <= MD5KEYS; i++) { 643132451Sroberto for (j = 0; j < 16; j++) { 644132451Sroberto while (1) { 645276158Sdes temp = arc4random() & 0xff; 646132451Sroberto if (temp == '#') 647132451Sroberto continue; 648132451Sroberto if (temp > 0x20 && temp < 0x7f) 649132451Sroberto break; 650132451Sroberto } 651132451Sroberto md5key[j] = (u_char)temp; 652132451Sroberto } 653132536Sroberto md5key[15] = '\0'; 654132451Sroberto fprintf(str, "%2d MD5 %16s # MD5 key\n", i, 655132451Sroberto md5key); 656132451Sroberto } 657132451Sroberto fclose(str); 658132451Sroberto fslink(id, hostname); 659132451Sroberto return (1); 660132451Sroberto} 661132451Sroberto#endif /* OPENSSL */ 662132451Sroberto 663132451Sroberto 664132451Sroberto#ifdef OPENSSL 665132451Sroberto/* 666132451Sroberto * Generate RSA public/private key pair 667132451Sroberto */ 668132451SrobertoEVP_PKEY * /* public/private key pair */ 669132451Srobertogen_rsa( 670132451Sroberto char *id /* file name id */ 671132451Sroberto ) 672132451Sroberto{ 673132451Sroberto EVP_PKEY *pkey; /* private key */ 674132451Sroberto RSA *rsa; /* RSA parameters and key pair */ 675132451Sroberto FILE *str; 676132451Sroberto 677132451Sroberto fprintf(stderr, "Generating RSA keys (%d bits)...\n", modulus); 678276158Sdes rsa = RSA_generate_key(modulus, 65537, cb, "RSA"); 679132451Sroberto fprintf(stderr, "\n"); 680132451Sroberto if (rsa == NULL) { 681132451Sroberto fprintf(stderr, "RSA generate keys fails\n%s\n", 682132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 683132451Sroberto rval = -1; 684132451Sroberto return (NULL); 685132451Sroberto } 686132451Sroberto 687132451Sroberto /* 688132451Sroberto * For signature encryption it is not necessary that the RSA 689132451Sroberto * parameters be strictly groomed and once in a while the 690132451Sroberto * modulus turns out to be non-prime. Just for grins, we check 691132451Sroberto * the primality. 692132451Sroberto */ 693132451Sroberto if (!RSA_check_key(rsa)) { 694132451Sroberto fprintf(stderr, "Invalid RSA key\n%s\n", 695132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 696132451Sroberto RSA_free(rsa); 697132451Sroberto rval = -1; 698132451Sroberto return (NULL); 699132451Sroberto } 700132451Sroberto 701132451Sroberto /* 702132451Sroberto * Write the RSA parameters and keys as a RSA private key 703132451Sroberto * encoded in PEM. 704132451Sroberto */ 705132451Sroberto str = fheader("RSAkey", hostname); 706132451Sroberto pkey = EVP_PKEY_new(); 707132451Sroberto EVP_PKEY_assign_RSA(pkey, rsa); 708132451Sroberto PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL, 709132451Sroberto NULL, 0, NULL, passwd2); 710132451Sroberto fclose(str); 711132451Sroberto if (debug) 712132451Sroberto RSA_print_fp(stdout, rsa, 0); 713132451Sroberto fslink(id, hostname); 714132451Sroberto return (pkey); 715132451Sroberto} 716132451Sroberto 717132451Sroberto 718132451Sroberto/* 719132451Sroberto * Generate DSA public/private key pair 720132451Sroberto */ 721132451SrobertoEVP_PKEY * /* public/private key pair */ 722132451Srobertogen_dsa( 723132451Sroberto char *id /* file name id */ 724132451Sroberto ) 725132451Sroberto{ 726132451Sroberto EVP_PKEY *pkey; /* private key */ 727132451Sroberto DSA *dsa; /* DSA parameters */ 728132451Sroberto u_char seed[20]; /* seed for parameters */ 729132451Sroberto FILE *str; 730132451Sroberto 731132451Sroberto /* 732132451Sroberto * Generate DSA parameters. 733132451Sroberto */ 734132451Sroberto fprintf(stderr, 735132451Sroberto "Generating DSA parameters (%d bits)...\n", modulus); 736132451Sroberto RAND_bytes(seed, sizeof(seed)); 737132451Sroberto dsa = DSA_generate_parameters(modulus, seed, sizeof(seed), NULL, 738132451Sroberto NULL, cb, "DSA"); 739132451Sroberto fprintf(stderr, "\n"); 740132451Sroberto if (dsa == NULL) { 741132451Sroberto fprintf(stderr, "DSA generate parameters fails\n%s\n", 742132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 743132451Sroberto rval = -1; 744132451Sroberto return (NULL); 745132451Sroberto } 746132451Sroberto 747132451Sroberto /* 748132451Sroberto * Generate DSA keys. 749132451Sroberto */ 750132451Sroberto fprintf(stderr, "Generating DSA keys (%d bits)...\n", modulus); 751132451Sroberto if (!DSA_generate_key(dsa)) { 752132451Sroberto fprintf(stderr, "DSA generate keys fails\n%s\n", 753132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 754132451Sroberto DSA_free(dsa); 755132451Sroberto rval = -1; 756132451Sroberto return (NULL); 757132451Sroberto } 758132451Sroberto 759132451Sroberto /* 760132451Sroberto * Write the DSA parameters and keys as a DSA private key 761132451Sroberto * encoded in PEM. 762132451Sroberto */ 763132451Sroberto str = fheader("DSAkey", hostname); 764132451Sroberto pkey = EVP_PKEY_new(); 765132451Sroberto EVP_PKEY_assign_DSA(pkey, dsa); 766132451Sroberto PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL, 767132451Sroberto NULL, 0, NULL, passwd2); 768132451Sroberto fclose(str); 769132451Sroberto if (debug) 770132451Sroberto DSA_print_fp(stdout, dsa, 0); 771132451Sroberto fslink(id, hostname); 772132451Sroberto return (pkey); 773132451Sroberto} 774132451Sroberto 775132451Sroberto 776132451Sroberto/* 777132451Sroberto * Generate Schnorr (IFF) parameters and keys 778132451Sroberto * 779132451Sroberto * The Schnorr (IFF)identity scheme is intended for use when 780132451Sroberto * certificates are generated by some other trusted certificate 781132451Sroberto * authority and the parameters cannot be conveyed in the certificate 782132451Sroberto * itself. For this purpose, new generations of IFF values must be 783132451Sroberto * securely transmitted to all members of the group before use. There 784132451Sroberto * are two kinds of files: server/client files that include private and 785132451Sroberto * public parameters and client files that include only public 786132451Sroberto * parameters. The scheme is self contained and independent of new 787132451Sroberto * generations of host keys, sign keys and certificates. 788132451Sroberto * 789132451Sroberto * The IFF values hide in a DSA cuckoo structure which uses the same 790132451Sroberto * parameters. The values are used by an identity scheme based on DSA 791132451Sroberto * cryptography and described in Stimson p. 285. The p is a 512-bit 792132451Sroberto * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1 793132451Sroberto * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a 794132451Sroberto * private random group key b (0 < b < q), then computes public 795132451Sroberto * v = g^(q - a). All values except the group key are known to all group 796132451Sroberto * members; the group key is known to the group servers, but not the 797132451Sroberto * group clients. Alice challenges Bob to confirm identity using the 798132451Sroberto * protocol described below. 799132451Sroberto */ 800132451SrobertoEVP_PKEY * /* DSA cuckoo nest */ 801132451Srobertogen_iff( 802132451Sroberto char *id /* file name id */ 803132451Sroberto ) 804132451Sroberto{ 805132451Sroberto EVP_PKEY *pkey; /* private key */ 806132451Sroberto DSA *dsa; /* DSA parameters */ 807132451Sroberto u_char seed[20]; /* seed for parameters */ 808132451Sroberto BN_CTX *ctx; /* BN working space */ 809132451Sroberto BIGNUM *b, *r, *k, *u, *v, *w; /* BN temp */ 810132451Sroberto FILE *str; 811132451Sroberto u_int temp; 812132451Sroberto 813132451Sroberto /* 814132451Sroberto * Generate DSA parameters for use as IFF parameters. 815132451Sroberto */ 816132451Sroberto fprintf(stderr, "Generating IFF parameters (%d bits)...\n", 817132451Sroberto modulus); 818132451Sroberto RAND_bytes(seed, sizeof(seed)); 819132451Sroberto dsa = DSA_generate_parameters(modulus, seed, sizeof(seed), NULL, 820132451Sroberto NULL, cb, "IFF"); 821132451Sroberto fprintf(stderr, "\n"); 822132451Sroberto if (dsa == NULL) { 823132451Sroberto fprintf(stderr, "DSA generate parameters fails\n%s\n", 824132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 825132451Sroberto rval = -1; 826132451Sroberto return (NULL);; 827132451Sroberto } 828132451Sroberto 829132451Sroberto /* 830132451Sroberto * Generate the private and public keys. The DSA parameters and 831132451Sroberto * these keys are distributed to all members of the group. 832132451Sroberto */ 833132451Sroberto fprintf(stderr, "Generating IFF keys (%d bits)...\n", modulus); 834132451Sroberto b = BN_new(); r = BN_new(); k = BN_new(); 835132451Sroberto u = BN_new(); v = BN_new(); w = BN_new(); ctx = BN_CTX_new(); 836132451Sroberto BN_rand(b, BN_num_bits(dsa->q), -1, 0); /* a */ 837132451Sroberto BN_mod(b, b, dsa->q, ctx); 838132451Sroberto BN_sub(v, dsa->q, b); 839132451Sroberto BN_mod_exp(v, dsa->g, v, dsa->p, ctx); /* g^(q - b) mod p */ 840132451Sroberto BN_mod_exp(u, dsa->g, b, dsa->p, ctx); /* g^b mod p */ 841132451Sroberto BN_mod_mul(u, u, v, dsa->p, ctx); 842132451Sroberto temp = BN_is_one(u); 843132451Sroberto fprintf(stderr, 844132451Sroberto "Confirm g^(q - b) g^b = 1 mod p: %s\n", temp == 1 ? 845132451Sroberto "yes" : "no"); 846132451Sroberto if (!temp) { 847132451Sroberto BN_free(b); BN_free(r); BN_free(k); 848132451Sroberto BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 849132451Sroberto rval = -1; 850132451Sroberto return (NULL); 851132451Sroberto } 852132451Sroberto dsa->priv_key = BN_dup(b); /* private key */ 853132451Sroberto dsa->pub_key = BN_dup(v); /* public key */ 854132451Sroberto 855132451Sroberto /* 856132451Sroberto * Here is a trial round of the protocol. First, Alice rolls 857132451Sroberto * random r (0 < r < q) and sends it to Bob. She needs only 858132451Sroberto * modulus q. 859132451Sroberto */ 860132451Sroberto BN_rand(r, BN_num_bits(dsa->q), -1, 0); /* r */ 861132451Sroberto BN_mod(r, r, dsa->q, ctx); 862132451Sroberto 863132451Sroberto /* 864132451Sroberto * Bob rolls random k (0 < k < q), computes y = k + b r mod q 865132451Sroberto * and x = g^k mod p, then sends (y, x) to Alice. He needs 866132451Sroberto * moduli p, q and the group key b. 867132451Sroberto */ 868132451Sroberto BN_rand(k, BN_num_bits(dsa->q), -1, 0); /* k, 0 < k < q */ 869132451Sroberto BN_mod(k, k, dsa->q, ctx); 870132451Sroberto BN_mod_mul(v, dsa->priv_key, r, dsa->q, ctx); /* b r mod q */ 871132451Sroberto BN_add(v, v, k); 872132451Sroberto BN_mod(v, v, dsa->q, ctx); /* y = k + b r mod q */ 873132451Sroberto BN_mod_exp(u, dsa->g, k, dsa->p, ctx); /* x = g^k mod p */ 874132451Sroberto 875132451Sroberto /* 876132451Sroberto * Alice computes g^y v^r and verifies the result is equal to x. 877132451Sroberto * She needs modulus p, generator g, and the public key v, as 878132451Sroberto * well as her original r. 879132451Sroberto */ 880132451Sroberto BN_mod_exp(v, dsa->g, v, dsa->p, ctx); /* g^y mod p */ 881132451Sroberto BN_mod_exp(w, dsa->pub_key, r, dsa->p, ctx); /* v^r */ 882132451Sroberto BN_mod_mul(v, w, v, dsa->p, ctx); /* product mod p */ 883132451Sroberto temp = BN_cmp(u, v); 884132451Sroberto fprintf(stderr, 885132451Sroberto "Confirm g^k = g^(k + b r) g^(q - b) r: %s\n", temp == 886132451Sroberto 0 ? "yes" : "no"); 887132451Sroberto BN_free(b); BN_free(r); BN_free(k); 888132451Sroberto BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 889132451Sroberto if (temp != 0) { 890132451Sroberto DSA_free(dsa); 891132451Sroberto rval = -1; 892132451Sroberto return (NULL); 893132451Sroberto } 894132451Sroberto 895132451Sroberto /* 896132451Sroberto * Write the IFF server parameters and keys as a DSA private key 897132451Sroberto * encoded in PEM. 898132451Sroberto * 899132451Sroberto * p modulus p 900132451Sroberto * q modulus q 901132451Sroberto * g generator g 902132451Sroberto * priv_key b 903132451Sroberto * public_key v 904132451Sroberto */ 905132451Sroberto str = fheader("IFFpar", trustname); 906132451Sroberto pkey = EVP_PKEY_new(); 907132451Sroberto EVP_PKEY_assign_DSA(pkey, dsa); 908132451Sroberto PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL, 909132451Sroberto NULL, 0, NULL, passwd2); 910132451Sroberto fclose(str); 911132451Sroberto if (debug) 912132451Sroberto DSA_print_fp(stdout, dsa, 0); 913132451Sroberto fslink(id, trustname); 914132451Sroberto return (pkey); 915132451Sroberto} 916132451Sroberto 917132451Sroberto 918132451Sroberto/* 919132451Sroberto * Generate Guillou-Quisquater (GQ) parameters and keys 920132451Sroberto * 921132451Sroberto * The Guillou-Quisquater (GQ) identity scheme is intended for use when 922132451Sroberto * the parameters, keys and certificates are generated by this program. 923132451Sroberto * The scheme uses a certificate extension field do convey the public 924132451Sroberto * key of a particular group identified by a group key known only to 925132451Sroberto * members of the group. The scheme is self contained and independent of 926132451Sroberto * new generations of host keys and sign keys. 927132451Sroberto * 928132451Sroberto * The GQ parameters hide in a RSA cuckoo structure which uses the same 929132451Sroberto * parameters. The values are used by an identity scheme based on RSA 930132451Sroberto * cryptography and described in Stimson p. 300 (with errors). The 512- 931132451Sroberto * bit public modulus is n = p q, where p and q are secret large primes. 932132451Sroberto * The TA rolls private random group key b as RSA exponent. These values 933132451Sroberto * are known to all group members. 934132451Sroberto * 935132451Sroberto * When rolling new certificates, a member recomputes the private and 936132451Sroberto * public keys. The private key u is a random roll, while the public key 937132451Sroberto * is the inverse obscured by the group key v = (u^-1)^b. These values 938132451Sroberto * replace the private and public keys normally generated by the RSA 939132451Sroberto * scheme. Alice challenges Bob to confirm identity using the protocol 940132451Sroberto * described below. 941132451Sroberto */ 942132451SrobertoEVP_PKEY * /* RSA cuckoo nest */ 943132451Srobertogen_gqpar( 944132451Sroberto char *id /* file name id */ 945132451Sroberto ) 946132451Sroberto{ 947132451Sroberto EVP_PKEY *pkey; /* private key */ 948132451Sroberto RSA *rsa; /* GQ parameters */ 949132451Sroberto BN_CTX *ctx; /* BN working space */ 950132451Sroberto FILE *str; 951132451Sroberto 952132451Sroberto /* 953132451Sroberto * Generate RSA parameters for use as GQ parameters. 954132451Sroberto */ 955132451Sroberto fprintf(stderr, 956132451Sroberto "Generating GQ parameters (%d bits)...\n", modulus); 957276158Sdes rsa = RSA_generate_key(modulus, 65537, cb, "GQ"); 958132451Sroberto fprintf(stderr, "\n"); 959132451Sroberto if (rsa == NULL) { 960132451Sroberto fprintf(stderr, "RSA generate keys fails\n%s\n", 961132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 962132451Sroberto rval = -1; 963132451Sroberto return (NULL); 964132451Sroberto } 965132451Sroberto 966132451Sroberto /* 967132451Sroberto * Generate the group key b, which is saved in the e member of 968132451Sroberto * the RSA structure. These values are distributed to all 969132451Sroberto * members of the group, but shielded from all other groups. We 970132451Sroberto * don't use all the parameters, but set the unused ones to a 971132451Sroberto * small number to minimize the file size. 972132451Sroberto */ 973132451Sroberto ctx = BN_CTX_new(); 974132451Sroberto BN_rand(rsa->e, BN_num_bits(rsa->n), -1, 0); /* b */ 975132451Sroberto BN_mod(rsa->e, rsa->e, rsa->n, ctx); 976132451Sroberto BN_copy(rsa->d, BN_value_one()); 977132451Sroberto BN_copy(rsa->p, BN_value_one()); 978132451Sroberto BN_copy(rsa->q, BN_value_one()); 979132451Sroberto BN_copy(rsa->dmp1, BN_value_one()); 980132451Sroberto BN_copy(rsa->dmq1, BN_value_one()); 981132451Sroberto BN_copy(rsa->iqmp, BN_value_one()); 982132451Sroberto 983132451Sroberto /* 984132451Sroberto * Write the GQ parameters as a RSA private key encoded in PEM. 985132451Sroberto * The public and private keys are filled in later. 986132451Sroberto * 987132451Sroberto * n modulus n 988132451Sroberto * e group key b 989132451Sroberto * (remaining values are not used) 990132451Sroberto */ 991132451Sroberto str = fheader("GQpar", trustname); 992132451Sroberto pkey = EVP_PKEY_new(); 993132451Sroberto EVP_PKEY_assign_RSA(pkey, rsa); 994132451Sroberto PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL, 995132451Sroberto NULL, 0, NULL, passwd2); 996132451Sroberto fclose(str); 997132451Sroberto if (debug) 998132451Sroberto RSA_print_fp(stdout, rsa, 0); 999132451Sroberto fslink(id, trustname); 1000132451Sroberto return (pkey); 1001132451Sroberto} 1002132451Sroberto 1003132451Sroberto 1004132451Sroberto/* 1005132451Sroberto * Update Guillou-Quisquater (GQ) parameters 1006132451Sroberto */ 1007132451SrobertoEVP_PKEY * /* RSA cuckoo nest */ 1008132451Srobertogen_gqkey( 1009132451Sroberto char *id, /* file name id */ 1010132451Sroberto EVP_PKEY *gqpar /* GQ parameters */ 1011132451Sroberto ) 1012132451Sroberto{ 1013132451Sroberto EVP_PKEY *pkey; /* private key */ 1014132451Sroberto RSA *rsa; /* RSA parameters */ 1015132451Sroberto BN_CTX *ctx; /* BN working space */ 1016132451Sroberto BIGNUM *u, *v, *g, *k, *r, *y; /* BN temps */ 1017132451Sroberto FILE *str; 1018132451Sroberto u_int temp; 1019132451Sroberto 1020132451Sroberto /* 1021132451Sroberto * Generate GQ keys. Note that the group key b is the e member 1022132451Sroberto * of 1023132451Sroberto * the GQ parameters. 1024132451Sroberto */ 1025132451Sroberto fprintf(stderr, "Updating GQ keys (%d bits)...\n", modulus); 1026132451Sroberto ctx = BN_CTX_new(); u = BN_new(); v = BN_new(); 1027132451Sroberto g = BN_new(); k = BN_new(); r = BN_new(); y = BN_new(); 1028132451Sroberto 1029132451Sroberto /* 1030132451Sroberto * When generating his certificate, Bob rolls random private key 1031132451Sroberto * u. 1032132451Sroberto */ 1033132451Sroberto rsa = gqpar->pkey.rsa; 1034132451Sroberto BN_rand(u, BN_num_bits(rsa->n), -1, 0); /* u */ 1035132451Sroberto BN_mod(u, u, rsa->n, ctx); 1036132451Sroberto BN_mod_inverse(v, u, rsa->n, ctx); /* u^-1 mod n */ 1037132451Sroberto BN_mod_mul(k, v, u, rsa->n, ctx); 1038132451Sroberto 1039132451Sroberto /* 1040132451Sroberto * Bob computes public key v = (u^-1)^b, which is saved in an 1041132451Sroberto * extension field on his certificate. We check that u^b v = 1042132451Sroberto * 1 mod n. 1043132451Sroberto */ 1044132451Sroberto BN_mod_exp(v, v, rsa->e, rsa->n, ctx); 1045132451Sroberto BN_mod_exp(g, u, rsa->e, rsa->n, ctx); /* u^b */ 1046132451Sroberto BN_mod_mul(g, g, v, rsa->n, ctx); /* u^b (u^-1)^b */ 1047132451Sroberto temp = BN_is_one(g); 1048132451Sroberto fprintf(stderr, 1049132451Sroberto "Confirm u^b (u^-1)^b = 1 mod n: %s\n", temp ? "yes" : 1050132451Sroberto "no"); 1051132451Sroberto if (!temp) { 1052132451Sroberto BN_free(u); BN_free(v); 1053132451Sroberto BN_free(g); BN_free(k); BN_free(r); BN_free(y); 1054132451Sroberto BN_CTX_free(ctx); 1055132451Sroberto RSA_free(rsa); 1056132451Sroberto rval = -1; 1057132451Sroberto return (NULL); 1058132451Sroberto } 1059132451Sroberto BN_copy(rsa->p, u); /* private key */ 1060132451Sroberto BN_copy(rsa->q, v); /* public key */ 1061132451Sroberto 1062132451Sroberto /* 1063132451Sroberto * Here is a trial run of the protocol. First, Alice rolls 1064132451Sroberto * random r (0 < r < n) and sends it to Bob. She needs only 1065132451Sroberto * modulus n from the parameters. 1066132451Sroberto */ 1067132451Sroberto BN_rand(r, BN_num_bits(rsa->n), -1, 0); /* r */ 1068132451Sroberto BN_mod(r, r, rsa->n, ctx); 1069132451Sroberto 1070132451Sroberto /* 1071132451Sroberto * Bob rolls random k (0 < k < n), computes y = k u^r mod n and 1072132451Sroberto * g = k^b mod n, then sends (y, g) to Alice. He needs modulus n 1073132451Sroberto * from the parameters and his private key u. 1074132451Sroberto */ 1075132451Sroberto BN_rand(k, BN_num_bits(rsa->n), -1, 0); /* k */ 1076132451Sroberto BN_mod(k, k, rsa->n, ctx); 1077132451Sroberto BN_mod_exp(y, rsa->p, r, rsa->n, ctx); /* u^r mod n */ 1078132451Sroberto BN_mod_mul(y, k, y, rsa->n, ctx); /* y = k u^r mod n */ 1079132451Sroberto BN_mod_exp(g, k, rsa->e, rsa->n, ctx); /* g = k^b mod n */ 1080132451Sroberto 1081132451Sroberto /* 1082132451Sroberto * Alice computes v^r y^b mod n and verifies the result is equal 1083132451Sroberto * to g. She needs modulus n, generator g and group key b from 1084132451Sroberto * the parameters and Bob's public key v = (u^-1)^b from his 1085132451Sroberto * certificate. 1086132451Sroberto */ 1087132451Sroberto BN_mod_exp(v, rsa->q, r, rsa->n, ctx); /* v^r mod n */ 1088132451Sroberto BN_mod_exp(y, y, rsa->e, rsa->n, ctx); /* y^b mod n */ 1089132451Sroberto BN_mod_mul(y, v, y, rsa->n, ctx); /* v^r y^b mod n */ 1090132451Sroberto temp = BN_cmp(y, g); 1091132451Sroberto fprintf(stderr, "Confirm g^k = v^r y^b mod n: %s\n", temp == 0 ? 1092132451Sroberto "yes" : "no"); 1093132451Sroberto BN_CTX_free(ctx); BN_free(u); BN_free(v); 1094132451Sroberto BN_free(g); BN_free(k); BN_free(r); BN_free(y); 1095132451Sroberto if (temp != 0) { 1096132451Sroberto RSA_free(rsa); 1097132451Sroberto rval = -1; 1098132451Sroberto return (NULL); 1099132451Sroberto } 1100132451Sroberto 1101132451Sroberto /* 1102132451Sroberto * Write the GQ parameters and keys as a RSA private key encoded 1103132451Sroberto * in PEM. 1104132451Sroberto * 1105132451Sroberto * n modulus n 1106132451Sroberto * e group key b 1107132451Sroberto * p private key u 1108132451Sroberto * q public key (u^-1)^b 1109132451Sroberto * (remaining values are not used) 1110132451Sroberto */ 1111132451Sroberto str = fheader("GQpar", trustname); 1112132451Sroberto pkey = EVP_PKEY_new(); 1113132451Sroberto EVP_PKEY_assign_RSA(pkey, rsa); 1114132451Sroberto PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL, 1115132451Sroberto NULL, 0, NULL, passwd2); 1116132451Sroberto fclose(str); 1117132451Sroberto if (debug) 1118132451Sroberto RSA_print_fp(stdout, rsa, 0); 1119132451Sroberto fslink(id, trustname); 1120132451Sroberto return (pkey); 1121132451Sroberto} 1122132451Sroberto 1123132451Sroberto 1124132451Sroberto/* 1125132451Sroberto * Generate Mu-Varadharajan (MV) parameters and keys 1126132451Sroberto * 1127132451Sroberto * The Mu-Varadharajan (MV) cryptosystem is useful when servers 1128132451Sroberto * broadcast messages to clients, but clients never send messages to 1129132451Sroberto * servers. There is one encryption key for the server and a separate 1130132451Sroberto * decryption key for each client. It operates something like a 1131132451Sroberto * pay-per-view satellite broadcasting system where the session key is 1132132451Sroberto * encrypted by the broadcaster and the decryption keys are held in a 1133132451Sroberto * tamperproof set-top box. We don't use it this way, but read on. 1134132451Sroberto * 1135132451Sroberto * The MV parameters and private encryption key hide in a DSA cuckoo 1136132451Sroberto * structure which uses the same parameters, but generated in a 1137132451Sroberto * different way. The values are used in an encryption scheme similar to 1138132451Sroberto * El Gamal cryptography and a polynomial formed from the expansion of 1139132451Sroberto * product terms (x - x[j]), as described in Mu, Y., and V. 1140132451Sroberto * Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001, 1141132451Sroberto * 223-231. The paper has significant errors and serious omissions. 1142132451Sroberto * 1143132451Sroberto * Let q be the product of n distinct primes s'[j] (j = 1...n), where 1144132451Sroberto * each s'[j] has m significant bits. Let p be a prime p = 2 * q + 1, so 1145132451Sroberto * that q and each s'[j] divide p - 1 and p has M = n * m + 1 1146132451Sroberto * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1) 1147132451Sroberto * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then 1148132451Sroberto * project into Zp* as exponents of g. Sometimes we have to compute an 1149132451Sroberto * inverse b^-1 of random b in Zq, but for that purpose we require 1150132451Sroberto * gcd(b, q) = 1. We expect M to be in the 500-bit range and n 1151132451Sroberto * relatively small, like 30. Associated with each s'[j] is an element 1152132451Sroberto * s[j] such that s[j] s'[j] = s'[j] mod q. We find s[j] as the quotient 1153132451Sroberto * (q + s'[j]) / s'[j]. These are the parameters of the scheme and they 1154132451Sroberto * are expensive to compute. 1155132451Sroberto * 1156132451Sroberto * We set up an instance of the scheme as follows. A set of random 1157132451Sroberto * values x[j] mod q (j = 1...n), are generated as the zeros of a 1158132451Sroberto * polynomial of order n. The product terms (x - x[j]) are expanded to 1159132451Sroberto * form coefficients a[i] mod q (i = 0...n) in powers of x. These are 1160132451Sroberto * used as exponents of the generator g mod p to generate the private 1161132451Sroberto * encryption key A. The pair (gbar, ghat) of public server keys and the 1162132451Sroberto * pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used 1163132451Sroberto * to construct the decryption keys. The devil is in the details. 1164132451Sroberto * 1165132451Sroberto * This routine generates a private encryption file including the 1166132451Sroberto * private encryption key E and public key (gbar, ghat). It then 1167132451Sroberto * generates decryption files including the private key (xbar[j], 1168132451Sroberto * xhat[j]) for each client. E is a permutation that encrypts a block 1169132451Sroberto * y = E x. The jth client computes the inverse permutation E^-1 = 1170132451Sroberto * gbar^xhat[j] ghat^xbar[j] and decrypts the block x = E^-1 y. 1171132451Sroberto * 1172132451Sroberto * The distinguishing characteristic of this scheme is the capability to 1173132451Sroberto * revoke keys. Included in the calculation of E, gbar and ghat is the 1174132451Sroberto * product s = prod(s'[j]) (j = 1...n) above. If the factor s'[j] is 1175132451Sroberto * subsequently removed from the product and E, gbar and ghat 1176132451Sroberto * recomputed, the jth client will no longer be able to compute E^-1 and 1177132451Sroberto * thus unable to decrypt the block. 1178132451Sroberto */ 1179132451SrobertoEVP_PKEY * /* DSA cuckoo nest */ 1180132451Srobertogen_mv( 1181132451Sroberto char *id /* file name id */ 1182132451Sroberto ) 1183132451Sroberto{ 1184132536Sroberto EVP_PKEY *pkey, *pkey1; /* private key */ 1185132451Sroberto DSA *dsa; /* DSA parameters */ 1186132451Sroberto DSA *sdsa; /* DSA parameters */ 1187132451Sroberto BN_CTX *ctx; /* BN working space */ 1188132451Sroberto BIGNUM **x; /* polynomial zeros vector */ 1189132451Sroberto BIGNUM **a; /* polynomial coefficient vector */ 1190132451Sroberto BIGNUM **g; /* public key vector */ 1191132451Sroberto BIGNUM **s, **s1; /* private enabling keys */ 1192132451Sroberto BIGNUM **xbar, **xhat; /* private keys vector */ 1193132451Sroberto BIGNUM *b; /* group key */ 1194132451Sroberto BIGNUM *b1; /* inverse group key */ 1195132451Sroberto BIGNUM *ss; /* enabling key */ 1196132451Sroberto BIGNUM *biga; /* master encryption key */ 1197132451Sroberto BIGNUM *bige; /* session encryption key */ 1198132451Sroberto BIGNUM *gbar, *ghat; /* public key */ 1199132451Sroberto BIGNUM *u, *v, *w; /* BN scratch */ 1200132451Sroberto int i, j, n; 1201132451Sroberto FILE *str; 1202132451Sroberto u_int temp; 1203132451Sroberto char ident[20]; 1204132451Sroberto 1205132451Sroberto /* 1206132451Sroberto * Generate MV parameters. 1207132451Sroberto * 1208132451Sroberto * The object is to generate a multiplicative group Zp* modulo a 1209132451Sroberto * prime p and a subset Zq mod q, where q is the product of n 1210132451Sroberto * distinct primes s'[j] (j = 1...n) and q divides p - 1. We 1211132451Sroberto * first generate n distinct primes, which may have to be 1212132451Sroberto * regenerated later. As a practical matter, it is tough to find 1213132451Sroberto * more than 31 distinct primes for modulus 512 or 61 primes for 1214132451Sroberto * modulus 1024. The latter can take several hundred iterations 1215132451Sroberto * and several minutes on a Sun Blade 1000. 1216132451Sroberto */ 1217132451Sroberto n = nkeys; 1218132451Sroberto fprintf(stderr, 1219132451Sroberto "Generating MV parameters for %d keys (%d bits)...\n", n, 1220132451Sroberto modulus / n); 1221132451Sroberto ctx = BN_CTX_new(); u = BN_new(); v = BN_new(); w = BN_new(); 1222132451Sroberto b = BN_new(); b1 = BN_new(); 1223132536Sroberto dsa = DSA_new(); 1224132451Sroberto dsa->p = BN_new(); 1225132451Sroberto dsa->q = BN_new(); 1226132451Sroberto dsa->g = BN_new(); 1227132451Sroberto s = malloc((n + 1) * sizeof(BIGNUM)); 1228132451Sroberto s1 = malloc((n + 1) * sizeof(BIGNUM)); 1229132451Sroberto for (j = 1; j <= n; j++) 1230132451Sroberto s1[j] = BN_new(); 1231132451Sroberto temp = 0; 1232132451Sroberto for (j = 1; j <= n; j++) { 1233132451Sroberto while (1) { 1234132451Sroberto fprintf(stderr, "Birthdays %d\r", temp); 1235132451Sroberto BN_generate_prime(s1[j], modulus / n, 0, NULL, 1236132451Sroberto NULL, NULL, NULL); 1237132451Sroberto for (i = 1; i < j; i++) { 1238132451Sroberto if (BN_cmp(s1[i], s1[j]) == 0) 1239132451Sroberto break; 1240132451Sroberto } 1241132451Sroberto if (i == j) 1242132451Sroberto break; 1243132451Sroberto temp++; 1244132451Sroberto } 1245132451Sroberto } 1246132451Sroberto fprintf(stderr, "Birthday keys rejected %d\n", temp); 1247132451Sroberto 1248132451Sroberto /* 1249132451Sroberto * Compute the modulus q as the product of the primes. Compute 1250132451Sroberto * the modulus p as 2 * q + 1 and test p for primality. If p 1251132451Sroberto * is composite, replace one of the primes with a new distinct 1252132451Sroberto * one and try again. Note that q will hardly be a secret since 1253132451Sroberto * we have to reveal p to servers and clients. However, 1254132451Sroberto * factoring q to find the primes should be adequately hard, as 1255132451Sroberto * this is the same problem considered hard in RSA. Question: is 1256132451Sroberto * it as hard to find n small prime factors totalling n bits as 1257132451Sroberto * it is to find two large prime factors totalling n bits? 1258132451Sroberto * Remember, the bad guy doesn't know n. 1259132451Sroberto */ 1260132451Sroberto temp = 0; 1261132451Sroberto while (1) { 1262132451Sroberto fprintf(stderr, "Duplicate keys rejected %d\r", ++temp); 1263132451Sroberto BN_one(dsa->q); 1264132451Sroberto for (j = 1; j <= n; j++) 1265132451Sroberto BN_mul(dsa->q, dsa->q, s1[j], ctx); 1266132451Sroberto BN_copy(dsa->p, dsa->q); 1267132451Sroberto BN_add(dsa->p, dsa->p, dsa->p); 1268132451Sroberto BN_add_word(dsa->p, 1); 1269132451Sroberto if (BN_is_prime(dsa->p, BN_prime_checks, NULL, ctx, 1270132451Sroberto NULL)) 1271132451Sroberto break; 1272132451Sroberto 1273132451Sroberto j = temp % n + 1; 1274132451Sroberto while (1) { 1275132451Sroberto BN_generate_prime(u, modulus / n, 0, 0, NULL, 1276132451Sroberto NULL, NULL); 1277132451Sroberto for (i = 1; i <= n; i++) { 1278132451Sroberto if (BN_cmp(u, s1[i]) == 0) 1279132451Sroberto break; 1280132451Sroberto } 1281132451Sroberto if (i > n) 1282132451Sroberto break; 1283132451Sroberto } 1284132451Sroberto BN_copy(s1[j], u); 1285132451Sroberto } 1286132451Sroberto fprintf(stderr, "Duplicate keys rejected %d\n", temp); 1287132451Sroberto 1288132451Sroberto /* 1289132451Sroberto * Compute the generator g using a random roll such that 1290132451Sroberto * gcd(g, p - 1) = 1 and g^q = 1. This is a generator of p, not 1291132451Sroberto * q. 1292132451Sroberto */ 1293132451Sroberto BN_copy(v, dsa->p); 1294132451Sroberto BN_sub_word(v, 1); 1295132451Sroberto while (1) { 1296132451Sroberto BN_rand(dsa->g, BN_num_bits(dsa->p) - 1, 0, 0); 1297132451Sroberto BN_mod(dsa->g, dsa->g, dsa->p, ctx); 1298132451Sroberto BN_gcd(u, dsa->g, v, ctx); 1299132451Sroberto if (!BN_is_one(u)) 1300132451Sroberto continue; 1301132451Sroberto 1302132451Sroberto BN_mod_exp(u, dsa->g, dsa->q, dsa->p, ctx); 1303132451Sroberto if (BN_is_one(u)) 1304132451Sroberto break; 1305132451Sroberto } 1306132451Sroberto 1307132451Sroberto /* 1308132451Sroberto * Compute s[j] such that s[j] * s'[j] = s'[j] for all j. The 1309132451Sroberto * easy way to do this is to compute q + s'[j] and divide the 1310132451Sroberto * result by s'[j]. Exercise for the student: prove the 1311132451Sroberto * remainder is always zero. 1312132451Sroberto */ 1313132451Sroberto for (j = 1; j <= n; j++) { 1314132451Sroberto s[j] = BN_new(); 1315132451Sroberto BN_add(s[j], dsa->q, s1[j]); 1316132451Sroberto BN_div(s[j], u, s[j], s1[j], ctx); 1317132451Sroberto } 1318132451Sroberto 1319132451Sroberto /* 1320132451Sroberto * Setup is now complete. Roll random polynomial roots x[j] 1321132451Sroberto * (0 < x[j] < q) for all j. While it may not be strictly 1322132451Sroberto * necessary, Make sure each root has no factors in common with 1323132451Sroberto * q. 1324132451Sroberto */ 1325132451Sroberto fprintf(stderr, 1326132451Sroberto "Generating polynomial coefficients for %d roots (%d bits)\n", 1327132451Sroberto n, BN_num_bits(dsa->q)); 1328132451Sroberto x = malloc((n + 1) * sizeof(BIGNUM)); 1329132451Sroberto for (j = 1; j <= n; j++) { 1330132451Sroberto x[j] = BN_new(); 1331132451Sroberto while (1) { 1332132451Sroberto BN_rand(x[j], BN_num_bits(dsa->q), 0, 0); 1333132451Sroberto BN_mod(x[j], x[j], dsa->q, ctx); 1334132451Sroberto BN_gcd(u, x[j], dsa->q, ctx); 1335132451Sroberto if (BN_is_one(u)) 1336132451Sroberto break; 1337132451Sroberto } 1338132451Sroberto } 1339132451Sroberto 1340132451Sroberto /* 1341132451Sroberto * Generate polynomial coefficients a[i] (i = 0...n) from the 1342132451Sroberto * expansion of root products (x - x[j]) mod q for all j. The 1343132451Sroberto * method is a present from Charlie Boncelet. 1344132451Sroberto */ 1345132451Sroberto a = malloc((n + 1) * sizeof(BIGNUM)); 1346132451Sroberto for (i = 0; i <= n; i++) { 1347132451Sroberto a[i] = BN_new(); 1348132451Sroberto BN_one(a[i]); 1349132451Sroberto } 1350132451Sroberto for (j = 1; j <= n; j++) { 1351132451Sroberto BN_zero(w); 1352132451Sroberto for (i = 0; i < j; i++) { 1353132451Sroberto BN_copy(u, dsa->q); 1354132451Sroberto BN_mod_mul(v, a[i], x[j], dsa->q, ctx); 1355132451Sroberto BN_sub(u, u, v); 1356132451Sroberto BN_add(u, u, w); 1357132451Sroberto BN_copy(w, a[i]); 1358132451Sroberto BN_mod(a[i], u, dsa->q, ctx); 1359132451Sroberto } 1360132451Sroberto } 1361132451Sroberto 1362132451Sroberto /* 1363132451Sroberto * Generate g[i] = g^a[i] mod p for all i and the generator g. 1364132451Sroberto */ 1365132451Sroberto fprintf(stderr, "Generating g[i] parameters\n"); 1366132451Sroberto g = malloc((n + 1) * sizeof(BIGNUM)); 1367132451Sroberto for (i = 0; i <= n; i++) { 1368132451Sroberto g[i] = BN_new(); 1369132451Sroberto BN_mod_exp(g[i], dsa->g, a[i], dsa->p, ctx); 1370132451Sroberto } 1371132451Sroberto 1372132451Sroberto /* 1373132451Sroberto * Verify prod(g[i]^(a[i] x[j]^i)) = 1 for all i, j; otherwise, 1374132451Sroberto * exit. Note the a[i] x[j]^i exponent is computed mod q, but 1375132451Sroberto * the g[i] is computed mod p. also note the expression given in 1376132451Sroberto * the paper is incorrect. 1377132451Sroberto */ 1378132451Sroberto temp = 1; 1379132451Sroberto for (j = 1; j <= n; j++) { 1380132451Sroberto BN_one(u); 1381132451Sroberto for (i = 0; i <= n; i++) { 1382132451Sroberto BN_set_word(v, i); 1383132451Sroberto BN_mod_exp(v, x[j], v, dsa->q, ctx); 1384132451Sroberto BN_mod_mul(v, v, a[i], dsa->q, ctx); 1385132451Sroberto BN_mod_exp(v, dsa->g, v, dsa->p, ctx); 1386132451Sroberto BN_mod_mul(u, u, v, dsa->p, ctx); 1387132451Sroberto } 1388132451Sroberto if (!BN_is_one(u)) 1389132451Sroberto temp = 0; 1390132451Sroberto } 1391132451Sroberto fprintf(stderr, 1392132451Sroberto "Confirm prod(g[i]^(x[j]^i)) = 1 for all i, j: %s\n", temp ? 1393132451Sroberto "yes" : "no"); 1394132451Sroberto if (!temp) { 1395132451Sroberto rval = -1; 1396132451Sroberto return (NULL); 1397132451Sroberto } 1398132451Sroberto 1399132451Sroberto /* 1400132451Sroberto * Make private encryption key A. Keep it around for awhile, 1401132451Sroberto * since it is expensive to compute. 1402132451Sroberto */ 1403132451Sroberto biga = BN_new(); 1404132451Sroberto BN_one(biga); 1405132451Sroberto for (j = 1; j <= n; j++) { 1406132451Sroberto for (i = 0; i < n; i++) { 1407132451Sroberto BN_set_word(v, i); 1408132451Sroberto BN_mod_exp(v, x[j], v, dsa->q, ctx); 1409132451Sroberto BN_mod_exp(v, g[i], v, dsa->p, ctx); 1410132451Sroberto BN_mod_mul(biga, biga, v, dsa->p, ctx); 1411132451Sroberto } 1412132451Sroberto } 1413132451Sroberto 1414132451Sroberto /* 1415132451Sroberto * Roll private random group key b mod q (0 < b < q), where 1416132451Sroberto * gcd(b, q) = 1 to guarantee b^1 exists, then compute b^-1 1417132451Sroberto * mod q. If b is changed, the client keys must be recomputed. 1418132451Sroberto */ 1419132451Sroberto while (1) { 1420132451Sroberto BN_rand(b, BN_num_bits(dsa->q), 0, 0); 1421132451Sroberto BN_mod(b, b, dsa->q, ctx); 1422132451Sroberto BN_gcd(u, b, dsa->q, ctx); 1423132451Sroberto if (BN_is_one(u)) 1424132451Sroberto break; 1425132451Sroberto } 1426132451Sroberto BN_mod_inverse(b1, b, dsa->q, ctx); 1427132451Sroberto 1428132451Sroberto /* 1429132451Sroberto * Make private client keys (xbar[j], xhat[j]) for all j. Note 1430132451Sroberto * that the keys for the jth client involve s[j], but not s'[j] 1431132451Sroberto * or the product s = prod(s'[j]) mod q, which is the enabling 1432132451Sroberto * key. 1433132451Sroberto */ 1434132451Sroberto xbar = malloc((n + 1) * sizeof(BIGNUM)); 1435132451Sroberto xhat = malloc((n + 1) * sizeof(BIGNUM)); 1436132451Sroberto for (j = 1; j <= n; j++) { 1437132451Sroberto xbar[j] = BN_new(); xhat[j] = BN_new(); 1438132451Sroberto BN_zero(xbar[j]); 1439132451Sroberto BN_set_word(v, n); 1440132451Sroberto for (i = 1; i <= n; i++) { 1441132451Sroberto if (i == j) 1442132451Sroberto continue; 1443132451Sroberto BN_mod_exp(u, x[i], v, dsa->q, ctx); 1444132451Sroberto BN_add(xbar[j], xbar[j], u); 1445132451Sroberto } 1446132451Sroberto BN_mod_mul(xbar[j], xbar[j], b1, dsa->q, ctx); 1447132451Sroberto BN_mod_exp(xhat[j], x[j], v, dsa->q, ctx); 1448132451Sroberto BN_mod_mul(xhat[j], xhat[j], s[j], dsa->q, ctx); 1449132451Sroberto } 1450132451Sroberto 1451132451Sroberto /* 1452132451Sroberto * The enabling key is initially q by construction. We can 1453132451Sroberto * revoke client j by dividing q by s'[j]. The quotient becomes 1454132451Sroberto * the enabling key s. Note we always have to revoke one key; 1455132451Sroberto * otherwise, the plaintext and cryptotext would be identical. 1456132451Sroberto */ 1457132451Sroberto ss = BN_new(); 1458132451Sroberto BN_copy(ss, dsa->q); 1459132451Sroberto BN_div(ss, u, dsa->q, s1[n], ctx); 1460132451Sroberto 1461132451Sroberto /* 1462132451Sroberto * Make private server encryption key E = A^s and public server 1463132451Sroberto * keys gbar = g^s mod p and ghat = g^(s b) mod p. The (gbar, 1464132451Sroberto * ghat) is the public key provided to the server, which uses it 1465132451Sroberto * to compute the session encryption key and public key included 1466132451Sroberto * in its messages. These values must be regenerated if the 1467132451Sroberto * enabling key is changed. 1468132451Sroberto */ 1469132451Sroberto bige = BN_new(); gbar = BN_new(); ghat = BN_new(); 1470132451Sroberto BN_mod_exp(bige, biga, ss, dsa->p, ctx); 1471132451Sroberto BN_mod_exp(gbar, dsa->g, ss, dsa->p, ctx); 1472132451Sroberto BN_mod_mul(v, ss, b, dsa->q, ctx); 1473132451Sroberto BN_mod_exp(ghat, dsa->g, v, dsa->p, ctx); 1474132451Sroberto 1475132451Sroberto /* 1476132451Sroberto * We produce the key media in three steps. The first step is to 1477132451Sroberto * generate the private values that do not depend on the 1478132451Sroberto * enabling key. These include the server values p, q, g, b, A 1479132451Sroberto * and the client values s'[j], xbar[j] and xhat[j] for each j. 1480132451Sroberto * The p, xbar[j] and xhat[j] values are encoded in private 1481132451Sroberto * files which are distributed to respective clients. The p, q, 1482132451Sroberto * g, A and s'[j] values (will be) written to a secret file to 1483132451Sroberto * be read back later. 1484132451Sroberto * 1485132451Sroberto * The secret file (will be) read back at some later time to 1486132451Sroberto * enable/disable individual keys and generate/regenerate the 1487132451Sroberto * enabling key s. The p, q, E, gbar and ghat values are written 1488132451Sroberto * to a secret file to be read back later by the server. 1489132451Sroberto * 1490132451Sroberto * The server reads the secret file and rolls the session key 1491132451Sroberto * k, which is used only once, then computes E^k, gbar^k and 1492132451Sroberto * ghat^k. The E^k is the session encryption key. The encrypted 1493132451Sroberto * data, gbar^k and ghat^k are transmtted to clients in an 1494132451Sroberto * extension field. The client receives the message and computes 1495132451Sroberto * x = (gbar^k)^xbar[j] (ghat^k)^xhat[j], finds the session 1496132451Sroberto * encryption key E^k as the inverse x^-1 and decrypts the data. 1497132451Sroberto */ 1498132451Sroberto BN_copy(dsa->g, bige); 1499132451Sroberto dsa->priv_key = BN_dup(gbar); 1500132451Sroberto dsa->pub_key = BN_dup(ghat); 1501132451Sroberto 1502132451Sroberto /* 1503132451Sroberto * Write the MV server parameters and keys as a DSA private key 1504132451Sroberto * encoded in PEM. 1505132451Sroberto * 1506132451Sroberto * p modulus p 1507132451Sroberto * q modulus q (used only to generate k) 1508132451Sroberto * g E mod p 1509132451Sroberto * priv_key gbar mod p 1510132451Sroberto * pub_key ghat mod p 1511132451Sroberto */ 1512132451Sroberto str = fheader("MVpar", trustname); 1513132451Sroberto pkey = EVP_PKEY_new(); 1514132451Sroberto EVP_PKEY_assign_DSA(pkey, dsa); 1515132451Sroberto PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL, 1516132451Sroberto NULL, 0, NULL, passwd2); 1517132451Sroberto fclose(str); 1518132451Sroberto if (debug) 1519132451Sroberto DSA_print_fp(stdout, dsa, 0); 1520132451Sroberto fslink(id, trustname); 1521132451Sroberto 1522132451Sroberto /* 1523132451Sroberto * Write the parameters and private key (xbar[j], xhat[j]) for 1524132451Sroberto * all j as a DSA private key encoded in PEM. It is used only by 1525132451Sroberto * the designated recipient(s) who pay a suitably outrageous fee 1526132451Sroberto * for its use. 1527132451Sroberto */ 1528132536Sroberto sdsa = DSA_new(); 1529132451Sroberto sdsa->p = BN_dup(dsa->p); 1530132451Sroberto sdsa->q = BN_dup(BN_value_one()); 1531132451Sroberto sdsa->g = BN_dup(BN_value_one()); 1532132451Sroberto sdsa->priv_key = BN_new(); 1533132451Sroberto sdsa->pub_key = BN_new(); 1534132451Sroberto for (j = 1; j <= n; j++) { 1535132451Sroberto BN_copy(sdsa->priv_key, xbar[j]); 1536132451Sroberto BN_copy(sdsa->pub_key, xhat[j]); 1537132451Sroberto BN_mod_exp(v, dsa->priv_key, sdsa->pub_key, dsa->p, 1538132451Sroberto ctx); 1539132451Sroberto BN_mod_exp(u, dsa->pub_key, sdsa->priv_key, dsa->p, 1540132451Sroberto ctx); 1541132451Sroberto BN_mod_mul(u, u, v, dsa->p, ctx); 1542132451Sroberto BN_mod_mul(u, u, dsa->g, dsa->p, ctx); 1543132451Sroberto BN_free(xbar[j]); BN_free(xhat[j]); 1544132451Sroberto BN_free(x[j]); BN_free(s[j]); BN_free(s1[j]); 1545132451Sroberto if (!BN_is_one(u)) { 1546132451Sroberto fprintf(stderr, "Revoke key %d\n", j); 1547132451Sroberto continue; 1548132451Sroberto } 1549132451Sroberto 1550132451Sroberto /* 1551132451Sroberto * Write the client parameters as a DSA private key 1552132451Sroberto * encoded in PEM. We don't make links for these. 1553132451Sroberto * 1554132451Sroberto * p modulus p 1555132451Sroberto * priv_key xbar[j] mod q 1556132451Sroberto * pub_key xhat[j] mod q 1557132451Sroberto * (remaining values are not used) 1558132451Sroberto */ 1559132451Sroberto sprintf(ident, "MVkey%d", j); 1560132451Sroberto str = fheader(ident, trustname); 1561132536Sroberto pkey1 = EVP_PKEY_new(); 1562132536Sroberto EVP_PKEY_set1_DSA(pkey1, sdsa); 1563132536Sroberto PEM_write_PrivateKey(str, pkey1, passwd2 ? 1564132451Sroberto EVP_des_cbc() : NULL, NULL, 0, NULL, passwd2); 1565132451Sroberto fclose(str); 1566132451Sroberto fprintf(stderr, "ntpkey_%s_%s.%lu\n", ident, trustname, 1567132451Sroberto epoch + JAN_1970); 1568132451Sroberto if (debug) 1569132451Sroberto DSA_print_fp(stdout, sdsa, 0); 1570132536Sroberto EVP_PKEY_free(pkey1); 1571132451Sroberto } 1572132451Sroberto 1573132451Sroberto /* 1574132451Sroberto * Free the countries. 1575132451Sroberto */ 1576132451Sroberto for (i = 0; i <= n; i++) { 1577132451Sroberto BN_free(a[i]); 1578132451Sroberto BN_free(g[i]); 1579132451Sroberto } 1580132451Sroberto BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); 1581132451Sroberto BN_free(b); BN_free(b1); BN_free(biga); BN_free(bige); 1582132451Sroberto BN_free(ss); BN_free(gbar); BN_free(ghat); 1583132536Sroberto DSA_free(sdsa); 1584132451Sroberto 1585132451Sroberto /* 1586132451Sroberto * Free the world. 1587132451Sroberto */ 1588132451Sroberto free(x); free(a); free(g); free(s); free(s1); 1589132451Sroberto free(xbar); free(xhat); 1590132451Sroberto return (pkey); 1591132451Sroberto} 1592132451Sroberto 1593132451Sroberto 1594132451Sroberto/* 1595132451Sroberto * Generate X509v3 scertificate. 1596132451Sroberto * 1597132451Sroberto * The certificate consists of the version number, serial number, 1598132451Sroberto * validity interval, issuer name, subject name and public key. For a 1599132451Sroberto * self-signed certificate, the issuer name is the same as the subject 1600132451Sroberto * name and these items are signed using the subject private key. The 1601132451Sroberto * validity interval extends from the current time to the same time one 1602132451Sroberto * year hence. For NTP purposes, it is convenient to use the NTP seconds 1603132451Sroberto * of the current time as the serial number. 1604132451Sroberto */ 1605132451Srobertoint 1606132451Srobertox509 ( 1607132451Sroberto EVP_PKEY *pkey, /* generic signature algorithm */ 1608132451Sroberto const EVP_MD *md, /* generic digest algorithm */ 1609132451Sroberto char *gqpub, /* identity extension (hex string) */ 1610132451Sroberto char *exten /* private cert extension */ 1611132451Sroberto ) 1612132451Sroberto{ 1613132451Sroberto X509 *cert; /* X509 certificate */ 1614132451Sroberto X509_NAME *subj; /* distinguished (common) name */ 1615132451Sroberto X509_EXTENSION *ex; /* X509v3 extension */ 1616132451Sroberto FILE *str; /* file handle */ 1617132451Sroberto ASN1_INTEGER *serial; /* serial number */ 1618132451Sroberto const char *id; /* digest/signature scheme name */ 1619132451Sroberto char pathbuf[MAXFILENAME + 1]; 1620132451Sroberto 1621132451Sroberto /* 1622132451Sroberto * Generate X509 self-signed certificate. 1623132451Sroberto * 1624132451Sroberto * Set the certificate serial to the NTP seconds for grins. Set 1625132451Sroberto * the version to 3. Set the subject name and issuer name to the 1626132451Sroberto * subject name in the request. Set the initial validity to the 1627132451Sroberto * current time and the final validity one year hence. 1628132451Sroberto */ 1629132451Sroberto id = OBJ_nid2sn(md->pkey_type); 1630132451Sroberto fprintf(stderr, "Generating certificate %s\n", id); 1631132451Sroberto cert = X509_new(); 1632132451Sroberto X509_set_version(cert, 2L); 1633132451Sroberto serial = ASN1_INTEGER_new(); 1634132451Sroberto ASN1_INTEGER_set(serial, epoch + JAN_1970); 1635132451Sroberto X509_set_serialNumber(cert, serial); 1636132451Sroberto ASN1_INTEGER_free(serial); 1637182007Sroberto X509_time_adj(X509_get_notBefore(cert), 0L, &epoch); 1638182007Sroberto X509_time_adj(X509_get_notAfter(cert), YEAR, &epoch); 1639132451Sroberto subj = X509_get_subject_name(cert); 1640132451Sroberto X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, 1641132451Sroberto (unsigned char *) hostname, strlen(hostname), -1, 0); 1642132451Sroberto subj = X509_get_issuer_name(cert); 1643132451Sroberto X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, 1644132451Sroberto (unsigned char *) trustname, strlen(trustname), -1, 0); 1645132451Sroberto if (!X509_set_pubkey(cert, pkey)) { 1646132451Sroberto fprintf(stderr, "Assign key fails\n%s\n", 1647132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 1648132451Sroberto X509_free(cert); 1649132451Sroberto rval = -1; 1650132451Sroberto return (0); 1651132451Sroberto } 1652132451Sroberto 1653132451Sroberto /* 1654132451Sroberto * Add X509v3 extensions if present. These represent the minimum 1655132451Sroberto * set defined in RFC3280 less the certificate_policy extension, 1656132451Sroberto * which is seriously obfuscated in OpenSSL. 1657132451Sroberto */ 1658132451Sroberto /* 1659132451Sroberto * The basic_constraints extension CA:TRUE allows servers to 1660132451Sroberto * sign client certficitates. 1661132451Sroberto */ 1662132451Sroberto fprintf(stderr, "%s: %s\n", LN_basic_constraints, 1663132451Sroberto BASIC_CONSTRAINTS); 1664132451Sroberto ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, 1665132451Sroberto BASIC_CONSTRAINTS); 1666132451Sroberto if (!X509_add_ext(cert, ex, -1)) { 1667132451Sroberto fprintf(stderr, "Add extension field fails\n%s\n", 1668132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 1669132451Sroberto rval = -1; 1670132451Sroberto return (0); 1671132451Sroberto } 1672132451Sroberto X509_EXTENSION_free(ex); 1673132451Sroberto 1674132451Sroberto /* 1675132451Sroberto * The key_usage extension designates the purposes the key can 1676132451Sroberto * be used for. 1677132451Sroberto */ 1678132451Sroberto fprintf(stderr, "%s: %s\n", LN_key_usage, KEY_USAGE); 1679132451Sroberto ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, KEY_USAGE); 1680132451Sroberto if (!X509_add_ext(cert, ex, -1)) { 1681132451Sroberto fprintf(stderr, "Add extension field fails\n%s\n", 1682132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 1683132451Sroberto rval = -1; 1684132451Sroberto return (0); 1685132451Sroberto } 1686132451Sroberto X509_EXTENSION_free(ex); 1687132451Sroberto /* 1688132451Sroberto * The subject_key_identifier is used for the GQ public key. 1689132451Sroberto * This should not be controversial. 1690132451Sroberto */ 1691132451Sroberto if (gqpub != NULL) { 1692132451Sroberto fprintf(stderr, "%s\n", LN_subject_key_identifier); 1693132451Sroberto ex = X509V3_EXT_conf_nid(NULL, NULL, 1694132451Sroberto NID_subject_key_identifier, gqpub); 1695132451Sroberto if (!X509_add_ext(cert, ex, -1)) { 1696132451Sroberto fprintf(stderr, 1697132451Sroberto "Add extension field fails\n%s\n", 1698132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 1699132451Sroberto rval = -1; 1700132451Sroberto return (0); 1701132451Sroberto } 1702132451Sroberto X509_EXTENSION_free(ex); 1703132451Sroberto } 1704132451Sroberto 1705132451Sroberto /* 1706132451Sroberto * The extended key usage extension is used for special purpose 1707132451Sroberto * here. The semantics probably do not conform to the designer's 1708132451Sroberto * intent and will likely change in future. 1709132451Sroberto * 1710132451Sroberto * "trustRoot" designates a root authority 1711132451Sroberto * "private" designates a private certificate 1712132451Sroberto */ 1713132451Sroberto if (exten != NULL) { 1714132451Sroberto fprintf(stderr, "%s: %s\n", LN_ext_key_usage, exten); 1715132451Sroberto ex = X509V3_EXT_conf_nid(NULL, NULL, 1716132451Sroberto NID_ext_key_usage, exten); 1717132451Sroberto if (!X509_add_ext(cert, ex, -1)) { 1718132451Sroberto fprintf(stderr, 1719132451Sroberto "Add extension field fails\n%s\n", 1720132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 1721132451Sroberto rval = -1; 1722132451Sroberto return (0); 1723132451Sroberto } 1724132451Sroberto X509_EXTENSION_free(ex); 1725132451Sroberto } 1726132451Sroberto 1727132451Sroberto /* 1728132451Sroberto * Sign and verify. 1729132451Sroberto */ 1730132451Sroberto X509_sign(cert, pkey, md); 1731132451Sroberto if (!X509_verify(cert, pkey)) { 1732132451Sroberto fprintf(stderr, "Verify %s certificate fails\n%s\n", id, 1733132451Sroberto ERR_error_string(ERR_get_error(), NULL)); 1734132451Sroberto X509_free(cert); 1735132451Sroberto rval = -1; 1736132451Sroberto return (0); 1737132451Sroberto } 1738132451Sroberto 1739132451Sroberto /* 1740132451Sroberto * Write the certificate encoded in PEM. 1741132451Sroberto */ 1742132451Sroberto sprintf(pathbuf, "%scert", id); 1743132451Sroberto str = fheader(pathbuf, hostname); 1744132451Sroberto PEM_write_X509(str, cert); 1745132451Sroberto fclose(str); 1746132451Sroberto if (debug) 1747132451Sroberto X509_print_fp(stdout, cert); 1748132451Sroberto X509_free(cert); 1749132451Sroberto fslink("cert", hostname); 1750132451Sroberto return (1); 1751132451Sroberto} 1752132451Sroberto 1753132451Sroberto#if 0 /* asn2ntp is not used */ 1754132451Sroberto/* 1755132451Sroberto * asn2ntp - convert ASN1_TIME time structure to NTP time 1756132451Sroberto */ 1757132451Srobertou_long 1758132451Srobertoasn2ntp ( 1759132451Sroberto ASN1_TIME *asn1time /* pointer to ASN1_TIME structure */ 1760132451Sroberto ) 1761132451Sroberto{ 1762132451Sroberto char *v; /* pointer to ASN1_TIME string */ 1763132451Sroberto struct tm tm; /* time decode structure time */ 1764132451Sroberto 1765132451Sroberto /* 1766132451Sroberto * Extract time string YYMMDDHHMMSSZ from ASN.1 time structure. 1767132451Sroberto * Note that the YY, MM, DD fields start with one, the HH, MM, 1768132451Sroberto * SS fiels start with zero and the Z character should be 'Z' 1769132451Sroberto * for UTC. Also note that years less than 50 map to years 1770132451Sroberto * greater than 100. Dontcha love ASN.1? 1771132451Sroberto */ 1772132451Sroberto if (asn1time->length > 13) 1773132451Sroberto return (-1); 1774132451Sroberto v = (char *)asn1time->data; 1775132451Sroberto tm.tm_year = (v[0] - '0') * 10 + v[1] - '0'; 1776132451Sroberto if (tm.tm_year < 50) 1777132451Sroberto tm.tm_year += 100; 1778132451Sroberto tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1; 1779132451Sroberto tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0'; 1780132451Sroberto tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0'; 1781132451Sroberto tm.tm_min = (v[8] - '0') * 10 + v[9] - '0'; 1782132451Sroberto tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0'; 1783132451Sroberto tm.tm_wday = 0; 1784132451Sroberto tm.tm_yday = 0; 1785132451Sroberto tm.tm_isdst = 0; 1786132451Sroberto return (mktime(&tm) + JAN_1970); 1787132451Sroberto} 1788132451Sroberto#endif 1789132451Sroberto 1790132451Sroberto/* 1791132451Sroberto * Callback routine 1792132451Sroberto */ 1793132451Srobertovoid 1794132451Srobertocb ( 1795132451Sroberto int n1, /* arg 1 */ 1796132451Sroberto int n2, /* arg 2 */ 1797132451Sroberto void *chr /* arg 3 */ 1798132451Sroberto ) 1799132451Sroberto{ 1800132451Sroberto switch (n1) { 1801132451Sroberto case 0: 1802132451Sroberto d0++; 1803132451Sroberto fprintf(stderr, "%s %d %d %lu\r", (char *)chr, n1, n2, 1804132451Sroberto d0); 1805132451Sroberto break; 1806132451Sroberto case 1: 1807132451Sroberto d1++; 1808132451Sroberto fprintf(stderr, "%s\t\t%d %d %lu\r", (char *)chr, n1, 1809132451Sroberto n2, d1); 1810132451Sroberto break; 1811132451Sroberto case 2: 1812132451Sroberto d2++; 1813132451Sroberto fprintf(stderr, "%s\t\t\t\t%d %d %lu\r", (char *)chr, 1814132451Sroberto n1, n2, d2); 1815132451Sroberto break; 1816132451Sroberto case 3: 1817132451Sroberto d3++; 1818132451Sroberto fprintf(stderr, "%s\t\t\t\t\t\t%d %d %lu\r", 1819132451Sroberto (char *)chr, n1, n2, d3); 1820132451Sroberto break; 1821132451Sroberto } 1822132451Sroberto} 1823132451Sroberto 1824132451Sroberto 1825132451Sroberto/* 1826132451Sroberto * Generate key 1827132451Sroberto */ 1828132451SrobertoEVP_PKEY * /* public/private key pair */ 1829132451Srobertogenkey( 1830132451Sroberto char *type, /* key type (RSA or DSA) */ 1831132451Sroberto char *id /* file name id */ 1832132451Sroberto ) 1833132451Sroberto{ 1834132451Sroberto if (type == NULL) 1835132451Sroberto return (NULL); 1836132451Sroberto if (strcmp(type, "RSA") == 0) 1837132451Sroberto return (gen_rsa(id)); 1838132451Sroberto 1839132451Sroberto else if (strcmp(type, "DSA") == 0) 1840132451Sroberto return (gen_dsa(id)); 1841132451Sroberto 1842132451Sroberto fprintf(stderr, "Invalid %s key type %s\n", id, type); 1843132451Sroberto rval = -1; 1844132451Sroberto return (NULL); 1845132451Sroberto} 1846132536Sroberto#endif /* OPENSSL */ 1847132451Sroberto 1848132451Sroberto 1849132451Sroberto/* 1850132451Sroberto * Generate file header 1851132451Sroberto */ 1852132451SrobertoFILE * 1853132451Srobertofheader ( 1854132451Sroberto const char *id, /* file name id */ 1855132451Sroberto const char *name /* owner name */ 1856132451Sroberto ) 1857132451Sroberto{ 1858132451Sroberto FILE *str; /* file handle */ 1859132451Sroberto 1860132451Sroberto sprintf(filename, "ntpkey_%s_%s.%lu", id, name, epoch + 1861132451Sroberto JAN_1970); 1862132451Sroberto if ((str = fopen(filename, "w")) == NULL) { 1863132451Sroberto perror("Write"); 1864132451Sroberto exit (-1); 1865132451Sroberto } 1866132451Sroberto fprintf(str, "# %s\n# %s", filename, ctime(&epoch)); 1867132451Sroberto return (str); 1868132451Sroberto} 1869132451Sroberto 1870132451Sroberto 1871132451Sroberto/* 1872132451Sroberto * Generate symbolic links 1873132451Sroberto */ 1874132451Srobertovoid 1875132451Srobertofslink( 1876132451Sroberto const char *id, /* file name id */ 1877132451Sroberto const char *name /* owner name */ 1878132451Sroberto ) 1879132451Sroberto{ 1880132451Sroberto char linkname[MAXFILENAME]; /* link name */ 1881132451Sroberto int temp; 1882132451Sroberto 1883132451Sroberto sprintf(linkname, "ntpkey_%s_%s", id, name); 1884132451Sroberto remove(linkname); 1885132451Sroberto temp = symlink(filename, linkname); 1886132451Sroberto if (temp < 0) 1887132451Sroberto perror(id); 1888132451Sroberto fprintf(stderr, "Generating new %s file and link\n", id); 1889132451Sroberto fprintf(stderr, "%s->%s\n", linkname, filename); 1890132451Sroberto} 1891