Annotation of embedaddon/ntp/util/ntp-keygen.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Program to generate cryptographic keys for ntp clients and servers
        !             3:  *
        !             4:  * This program generates password encrypted data files for use with the
        !             5:  * Autokey security protocol and Network Time Protocol Version 4. Files
        !             6:  * are prefixed with a header giving the name and date of creation
        !             7:  * followed by a type-specific descriptive label and PEM-encoded data
        !             8:  * structure compatible with programs of the OpenSSL library.
        !             9:  *
        !            10:  * All file names are like "ntpkey_<type>_<hostname>.<filestamp>", where
        !            11:  * <type> is the file type, <hostname> the generating host name and
        !            12:  * <filestamp> the generation time in NTP seconds. The NTP programs
        !            13:  * expect generic names such as "ntpkey_<type>_whimsy.udel.edu" with the
        !            14:  * association maintained by soft links. Following is a list of file
        !            15:  * types; the first line is the file name and the second link name.
        !            16:  *
        !            17:  * ntpkey_MD5key_<hostname>.<filestamp>
        !            18:  *     MD5 (128-bit) keys used to compute message digests in symmetric
        !            19:  *     key cryptography
        !            20:  *
        !            21:  * ntpkey_RSAhost_<hostname>.<filestamp>
        !            22:  * ntpkey_host_<hostname>
        !            23:  *     RSA private/public host key pair used for public key signatures
        !            24:  *
        !            25:  * ntpkey_RSAsign_<hostname>.<filestamp>
        !            26:  * ntpkey_sign_<hostname>
        !            27:  *     RSA private/public sign key pair used for public key signatures
        !            28:  *
        !            29:  * ntpkey_DSAsign_<hostname>.<filestamp>
        !            30:  * ntpkey_sign_<hostname>
        !            31:  *     DSA Private/public sign key pair used for public key signatures
        !            32:  *
        !            33:  * Available digest/signature schemes
        !            34:  *
        !            35:  * RSA:        RSA-MD2, RSA-MD5, RSA-SHA, RSA-SHA1, RSA-MDC2, EVP-RIPEMD160
        !            36:  * DSA:        DSA-SHA, DSA-SHA1
        !            37:  *
        !            38:  * ntpkey_XXXcert_<hostname>.<filestamp>
        !            39:  * ntpkey_cert_<hostname>
        !            40:  *     X509v3 certificate using RSA or DSA public keys and signatures.
        !            41:  *     XXX is a code identifying the message digest and signature
        !            42:  *     encryption algorithm
        !            43:  *
        !            44:  * Identity schemes. The key type par is used for the challenge; the key
        !            45:  * type key is used for the response.
        !            46:  *
        !            47:  * ntpkey_IFFkey_<groupname>.<filestamp>
        !            48:  * ntpkey_iffkey_<groupname>
        !            49:  *     Schnorr (IFF) identity parameters and keys
        !            50:  *
        !            51:  * ntpkey_GQkey_<groupname>.<filestamp>,
        !            52:  * ntpkey_gqkey_<groupname>
        !            53:  *     Guillou-Quisquater (GQ) identity parameters and keys
        !            54:  *
        !            55:  * ntpkey_MVkeyX_<groupname>.<filestamp>,
        !            56:  * ntpkey_mvkey_<groupname>
        !            57:  *     Mu-Varadharajan (MV) identity parameters and keys
        !            58:  *
        !            59:  * Note: Once in a while because of some statistical fluke this program
        !            60:  * fails to generate and verify some cryptographic data, as indicated by
        !            61:  * exit status -1. In this case simply run the program again. If the
        !            62:  * program does complete with exit code 0, the data are correct as
        !            63:  * verified.
        !            64:  *
        !            65:  * These cryptographic routines are characterized by the prime modulus
        !            66:  * size in bits. The default value of 512 bits is a compromise between
        !            67:  * cryptographic strength and computing time and is ordinarily
        !            68:  * considered adequate for this application. The routines have been
        !            69:  * tested with sizes of 256, 512, 1024 and 2048 bits. Not all message
        !            70:  * digest and signature encryption schemes work with sizes less than 512
        !            71:  * bits. The computing time for sizes greater than 2048 bits is
        !            72:  * prohibitive on all but the fastest processors. An UltraSPARC Blade
        !            73:  * 1000 took something over nine minutes to generate and verify the
        !            74:  * values with size 2048. An old SPARC IPC would take a week.
        !            75:  *
        !            76:  * The OpenSSL library used by this program expects a random seed file.
        !            77:  * As described in the OpenSSL documentation, the file name defaults to
        !            78:  * first the RANDFILE environment variable in the user's home directory
        !            79:  * and then .rnd in the user's home directory.
        !            80:  */
        !            81: #ifdef HAVE_CONFIG_H
        !            82: # include <config.h>
        !            83: #endif
        !            84: #include <string.h>
        !            85: #include <stdio.h>
        !            86: #include <stdlib.h>
        !            87: #include <unistd.h>
        !            88: #include <sys/stat.h>
        !            89: #include <sys/time.h>
        !            90: #include <sys/types.h>
        !            91: #include "ntp_types.h"
        !            92: #include "ntp_random.h"
        !            93: #include "ntp_stdlib.h"
        !            94: #include "ntp_assert.h"
        !            95: 
        !            96: #include "ntp_libopts.h"
        !            97: #include "ntp-keygen-opts.h"
        !            98: 
        !            99: #ifdef OPENSSL
        !           100: #include "openssl/bn.h"
        !           101: #include "openssl/evp.h"
        !           102: #include "openssl/err.h"
        !           103: #include "openssl/rand.h"
        !           104: #include "openssl/pem.h"
        !           105: #include "openssl/x509v3.h"
        !           106: #include <openssl/objects.h>
        !           107: #endif /* OPENSSL */
        !           108: #include <ssl_applink.c>
        !           109: 
        !           110: /*
        !           111:  * Cryptodefines
        !           112:  */
        !           113: #define        MD5KEYS         10      /* number of keys generated of each type */
        !           114: #define        MD5SIZE         20      /* maximum key size */
        !           115: #define        JAN_1970        2208988800UL /* NTP seconds */
        !           116: #define YEAR           ((long)60*60*24*365) /* one year in seconds */
        !           117: #define MAXFILENAME    256     /* max file name length */
        !           118: #define MAXHOSTNAME    256     /* max host name length */
        !           119: #ifdef OPENSSL
        !           120: #define        PLEN            512     /* default prime modulus size (bits) */
        !           121: #define        ILEN            256     /* default identity modulus size (bits) */
        !           122: #define        MVMAX           100     /* max MV parameters */
        !           123: 
        !           124: /*
        !           125:  * Strings used in X509v3 extension fields
        !           126:  */
        !           127: #define KEY_USAGE              "digitalSignature,keyCertSign"
        !           128: #define BASIC_CONSTRAINTS      "critical,CA:TRUE"
        !           129: #define EXT_KEY_PRIVATE                "private"
        !           130: #define EXT_KEY_TRUST          "trustRoot"
        !           131: #endif /* OPENSSL */
        !           132: 
        !           133: /*
        !           134:  * Prototypes
        !           135:  */
        !           136: FILE   *fheader        (const char *, const char *, const char *);
        !           137: int    gen_md5         (char *);
        !           138: #ifdef OPENSSL
        !           139: EVP_PKEY *gen_rsa      (char *);
        !           140: EVP_PKEY *gen_dsa      (char *);
        !           141: EVP_PKEY *gen_iffkey   (char *);
        !           142: EVP_PKEY *gen_gqkey    (char *);
        !           143: EVP_PKEY *gen_mvkey    (char *, EVP_PKEY **);
        !           144: void   gen_mvserv      (char *, EVP_PKEY **);
        !           145: int    x509            (EVP_PKEY *, const EVP_MD *, char *, char *,
        !           146:                            char *);
        !           147: void   cb              (int, int, void *);
        !           148: EVP_PKEY *genkey       (char *, char *);
        !           149: EVP_PKEY *readkey      (char *, char *, u_int *, EVP_PKEY **);
        !           150: void   writekey        (char *, char *, u_int *, EVP_PKEY **);
        !           151: u_long asn2ntp         (ASN1_TIME *);
        !           152: #endif /* OPENSSL */
        !           153: 
        !           154: /*
        !           155:  * Program variables
        !           156:  */
        !           157: extern char *optarg;           /* command line argument */
        !           158: char   *progname;
        !           159: volatile int   debug = 0;              /* debug, not de bug */
        !           160: #ifdef OPENSSL
        !           161: u_int  modulus = PLEN;         /* prime modulus size (bits) */
        !           162: u_int  modulus2 = ILEN;        /* identity modulus size (bits) */
        !           163: #endif
        !           164: int    nkeys;                  /* MV keys */
        !           165: time_t epoch;                  /* Unix epoch (seconds) since 1970 */
        !           166: u_int  fstamp;                 /* NTP filestamp */
        !           167: char   *hostname = NULL;       /* host name (subject name) */
        !           168: char   *groupname = NULL;      /* trusted host name (issuer name) */
        !           169: char   filename[MAXFILENAME + 1]; /* file name */
        !           170: char   *passwd1 = NULL;        /* input private key password */
        !           171: char   *passwd2 = NULL;        /* output private key password */
        !           172: #ifdef OPENSSL
        !           173: long   d0, d1, d2, d3;         /* callback counters */
        !           174: #endif /* OPENSSL */
        !           175: 
        !           176: #ifdef SYS_WINNT
        !           177: BOOL init_randfile();
        !           178: 
        !           179: /*
        !           180:  * Don't try to follow symbolic links
        !           181:  */
        !           182: int
        !           183: readlink(char *link, char *file, int len)
        !           184: {
        !           185:        return (-1);
        !           186: }
        !           187: 
        !           188: /*
        !           189:  * Don't try to create a symbolic link for now.
        !           190:  * Just move the file to the name you need.
        !           191:  */
        !           192: int
        !           193: symlink(char *filename, char *linkname) {
        !           194:        DeleteFile(linkname);
        !           195:        MoveFile(filename, linkname);
        !           196:        return (0);
        !           197: }
        !           198: void
        !           199: InitWin32Sockets() {
        !           200:        WORD wVersionRequested;
        !           201:        WSADATA wsaData;
        !           202:        wVersionRequested = MAKEWORD(2,0);
        !           203:        if (WSAStartup(wVersionRequested, &wsaData))
        !           204:        {
        !           205:                fprintf(stderr, "No useable winsock.dll\n");
        !           206:                exit(1);
        !           207:        }
        !           208: }
        !           209: #endif /* SYS_WINNT */
        !           210: 
        !           211: /*
        !           212:  * Main program
        !           213:  */
        !           214: int
        !           215: main(
        !           216:        int     argc,           /* command line options */
        !           217:        char    **argv
        !           218:        )
        !           219: {
        !           220:        struct timeval tv;      /* initialization vector */
        !           221:        int     md5key = 0;     /* generate MD5 keys */
        !           222: #ifdef OPENSSL
        !           223:        X509    *cert = NULL;   /* X509 certificate */
        !           224:        X509_EXTENSION *ext;    /* X509v3 extension */
        !           225:        EVP_PKEY *pkey_host = NULL; /* host key */
        !           226:        EVP_PKEY *pkey_sign = NULL; /* sign key */
        !           227:        EVP_PKEY *pkey_iffkey = NULL; /* IFF sever keys */
        !           228:        EVP_PKEY *pkey_gqkey = NULL; /* GQ server keys */
        !           229:        EVP_PKEY *pkey_mvkey = NULL; /* MV trusted agen keys */
        !           230:        EVP_PKEY *pkey_mvpar[MVMAX]; /* MV cleient keys */
        !           231:        int     hostkey = 0;    /* generate RSA keys */
        !           232:        int     iffkey = 0;     /* generate IFF keys */
        !           233:        int     gqkey = 0;      /* generate GQ keys */
        !           234:        int     mvkey = 0;      /* update MV keys */
        !           235:        int     mvpar = 0;      /* generate MV parameters */
        !           236:        char    *sign = NULL;   /* sign key */
        !           237:        EVP_PKEY *pkey = NULL;  /* temp key */
        !           238:        const EVP_MD *ectx;     /* EVP digest */
        !           239:        char    pathbuf[MAXFILENAME + 1];
        !           240:        const char *scheme = NULL; /* digest/signature scheme */
        !           241:        char    *exten = NULL;  /* private extension */
        !           242:        char    *grpkey = NULL; /* identity extension */
        !           243:        int     nid;            /* X509 digest/signature scheme */
        !           244:        FILE    *fstr = NULL;   /* file handle */
        !           245: #define iffsw   HAVE_OPT(ID_KEY)
        !           246: #endif /* OPENSSL */
        !           247:        char    hostbuf[MAXHOSTNAME + 1];
        !           248:        char    groupbuf[MAXHOSTNAME + 1];
        !           249: 
        !           250:        progname = argv[0];
        !           251: 
        !           252: #ifdef SYS_WINNT
        !           253:        /* Initialize before OpenSSL checks */
        !           254:        InitWin32Sockets();
        !           255:        if (!init_randfile())
        !           256:                fprintf(stderr, "Unable to initialize .rnd file\n");
        !           257:        ssl_applink();
        !           258: #endif
        !           259: 
        !           260: #ifdef OPENSSL
        !           261:        ssl_check_version();
        !           262: #endif /* OPENSSL */
        !           263: 
        !           264:        /*
        !           265:         * Process options, initialize host name and timestamp.
        !           266:         */
        !           267:        gethostname(hostbuf, MAXHOSTNAME);
        !           268:        hostname = hostbuf;
        !           269:        gettimeofday(&tv, 0);
        !           270: 
        !           271:        epoch = tv.tv_sec;
        !           272: 
        !           273:        {
        !           274:                int optct = ntpOptionProcess(&ntp_keygenOptions,
        !           275:                                             argc, argv);
        !           276:                argc -= optct;
        !           277:                argv += optct;
        !           278:        }
        !           279: 
        !           280: #ifdef OPENSSL
        !           281:        if (SSLeay() == SSLEAY_VERSION_NUMBER)
        !           282:                fprintf(stderr, "Using OpenSSL version %s\n",
        !           283:                        SSLeay_version(SSLEAY_VERSION));
        !           284:        else
        !           285:                fprintf(stderr, "Built against OpenSSL %s, using version %s\n",
        !           286:                        OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
        !           287: #endif /* OPENSSL */
        !           288: 
        !           289:        debug = DESC(DEBUG_LEVEL).optOccCt;
        !           290:        if (HAVE_OPT( MD5KEY ))
        !           291:                md5key++;
        !           292: 
        !           293: #ifdef OPENSSL
        !           294:        passwd1 = hostbuf;
        !           295:        if (HAVE_OPT( PVT_PASSWD ))
        !           296:                passwd1 = strdup(OPT_ARG( PVT_PASSWD ));
        !           297: 
        !           298:        if (HAVE_OPT( GET_PVT_PASSWD ))
        !           299:                passwd2 = strdup(OPT_ARG( GET_PVT_PASSWD ));
        !           300: 
        !           301:        if (HAVE_OPT( HOST_KEY ))
        !           302:                hostkey++;
        !           303: 
        !           304:        if (HAVE_OPT( SIGN_KEY ))
        !           305:                sign = strdup(OPT_ARG( SIGN_KEY ));
        !           306: 
        !           307:        if (HAVE_OPT( GQ_PARAMS ))
        !           308:                gqkey++;
        !           309: 
        !           310:        if (HAVE_OPT( IFFKEY ))
        !           311:                iffkey++;
        !           312: 
        !           313:        if (HAVE_OPT( MV_PARAMS )) {
        !           314:                mvkey++;
        !           315:                nkeys = OPT_VALUE_MV_PARAMS;
        !           316:        }
        !           317:        if (HAVE_OPT( MV_KEYS )) {
        !           318:                mvpar++;
        !           319:                nkeys = OPT_VALUE_MV_KEYS;
        !           320:        }
        !           321:        if (HAVE_OPT( MODULUS ))
        !           322:                modulus = OPT_VALUE_MODULUS;
        !           323: 
        !           324:        if (HAVE_OPT( CERTIFICATE ))
        !           325:                scheme = OPT_ARG( CERTIFICATE );
        !           326: 
        !           327:        if (HAVE_OPT( SUBJECT_NAME ))
        !           328:                hostname = strdup(OPT_ARG( SUBJECT_NAME ));
        !           329: 
        !           330:        if (HAVE_OPT( ISSUER_NAME ))
        !           331:                groupname = strdup(OPT_ARG( ISSUER_NAME ));
        !           332: 
        !           333:        if (HAVE_OPT( PVT_CERT ))
        !           334:                exten = EXT_KEY_PRIVATE;
        !           335: 
        !           336:        if (HAVE_OPT( TRUSTED_CERT ))
        !           337:                exten = EXT_KEY_TRUST;
        !           338: 
        !           339:        /*
        !           340:         * Seed random number generator and grow weeds.
        !           341:         */
        !           342:        ERR_load_crypto_strings();
        !           343:        OpenSSL_add_all_algorithms();
        !           344:        if (!RAND_status()) {
        !           345:                u_int   temp;
        !           346: 
        !           347:                if (RAND_file_name(pathbuf, MAXFILENAME) == NULL) {
        !           348:                        fprintf(stderr, "RAND_file_name %s\n",
        !           349:                            ERR_error_string(ERR_get_error(), NULL));
        !           350:                        exit (-1);
        !           351:                }
        !           352:                temp = RAND_load_file(pathbuf, -1);
        !           353:                if (temp == 0) {
        !           354:                        fprintf(stderr,
        !           355:                            "RAND_load_file %s not found or empty\n",
        !           356:                            pathbuf);
        !           357:                        exit (-1);
        !           358:                }
        !           359:                fprintf(stderr,
        !           360:                    "Random seed file %s %u bytes\n", pathbuf, temp);
        !           361:                RAND_add(&epoch, sizeof(epoch), 4.0);
        !           362:        }
        !           363: 
        !           364:        /*
        !           365:         * Load previous certificate if available.
        !           366:         */
        !           367:        sprintf(filename, "ntpkey_cert_%s", hostname);
        !           368:        if ((fstr = fopen(filename, "r")) != NULL) {
        !           369:                cert = PEM_read_X509(fstr, NULL, NULL, NULL);
        !           370:                fclose(fstr);
        !           371:        }
        !           372:        if (cert != NULL) {
        !           373: 
        !           374:                /*
        !           375:                 * Extract subject name.
        !           376:                 */
        !           377:                X509_NAME_oneline(X509_get_subject_name(cert), groupbuf,
        !           378:                    MAXFILENAME);
        !           379: 
        !           380:                /*
        !           381:                 * Extract digest/signature scheme.
        !           382:                 */
        !           383:                if (scheme == NULL) {
        !           384:                        nid = OBJ_obj2nid(cert->cert_info->
        !           385:                            signature->algorithm);
        !           386:                        scheme = OBJ_nid2sn(nid);
        !           387:                }
        !           388: 
        !           389:                /*
        !           390:                 * If a key_usage extension field is present, determine
        !           391:                 * whether this is a trusted or private certificate.
        !           392:                 */
        !           393:                if (exten == NULL) {
        !           394:                        BIO     *bp;
        !           395:                        int     i, cnt;
        !           396:                        char    *ptr;
        !           397: 
        !           398:                        ptr = strstr(groupbuf, "CN=");
        !           399:                        cnt = X509_get_ext_count(cert);
        !           400:                        for (i = 0; i < cnt; i++) {
        !           401:                                ext = X509_get_ext(cert, i);
        !           402:                                if (OBJ_obj2nid(ext->object) ==
        !           403:                                    NID_ext_key_usage) {
        !           404:                                        bp = BIO_new(BIO_s_mem());
        !           405:                                        X509V3_EXT_print(bp, ext, 0, 0);
        !           406:                                        BIO_gets(bp, pathbuf,
        !           407:                                            MAXFILENAME);
        !           408:                                        BIO_free(bp);
        !           409:                                        if (strcmp(pathbuf,
        !           410:                                            "Trust Root") == 0)
        !           411:                                                exten = EXT_KEY_TRUST;
        !           412:                                        else if (strcmp(pathbuf,
        !           413:                                            "Private") == 0)
        !           414:                                                exten = EXT_KEY_PRIVATE;
        !           415:                                        if (groupname == NULL)
        !           416:                                                groupname = ptr + 3;
        !           417:                                }
        !           418:                        }
        !           419:                }
        !           420:        }
        !           421:        if (scheme == NULL)
        !           422:                scheme = "RSA-MD5";
        !           423:        if (groupname == NULL)
        !           424:                groupname = hostname;
        !           425:        fprintf(stderr, "Using host %s group %s\n", hostname,
        !           426:            groupname);
        !           427:        if ((iffkey || gqkey || mvkey) && exten == NULL)
        !           428:                fprintf(stderr,
        !           429:                    "Warning: identity files may not be useful with a nontrusted certificate.\n");
        !           430: #endif /* OPENSSL */
        !           431: 
        !           432:        /*
        !           433:         * Create new unencrypted MD5 keys file if requested. If this
        !           434:         * option is selected, ignore all other options.
        !           435:         */
        !           436:        if (md5key) {
        !           437:                gen_md5("md5");
        !           438:                exit (0);
        !           439:        }
        !           440: 
        !           441: #ifdef OPENSSL
        !           442:        /*
        !           443:         * Create a new encrypted RSA host key file if requested;
        !           444:         * otherwise, look for an existing host key file. If not found,
        !           445:         * create a new encrypted RSA host key file. If that fails, go
        !           446:         * no further.
        !           447:         */
        !           448:        if (hostkey)
        !           449:                pkey_host = genkey("RSA", "host");
        !           450:        if (pkey_host == NULL) {
        !           451:                sprintf(filename, "ntpkey_host_%s", hostname);
        !           452:                pkey_host = readkey(filename, passwd1, &fstamp, NULL);
        !           453:                if (pkey_host != NULL) {
        !           454:                        readlink(filename, filename, sizeof(filename));
        !           455:                        fprintf(stderr, "Using host key %s\n",
        !           456:                            filename);
        !           457:                } else {
        !           458:                        pkey_host = genkey("RSA", "host");
        !           459:                }
        !           460:        }
        !           461:        if (pkey_host == NULL) {
        !           462:                fprintf(stderr, "Generating host key fails\n");
        !           463:                exit (-1);
        !           464:        }
        !           465: 
        !           466:        /*
        !           467:         * Create new encrypted RSA or DSA sign keys file if requested;
        !           468:         * otherwise, look for an existing sign key file. If not found,
        !           469:         * use the host key instead.
        !           470:         */
        !           471:        if (sign != NULL)
        !           472:                pkey_sign = genkey(sign, "sign");
        !           473:        if (pkey_sign == NULL) {
        !           474:                sprintf(filename, "ntpkey_sign_%s", hostname);
        !           475:                pkey_sign = readkey(filename, passwd1, &fstamp, NULL);
        !           476:                if (pkey_sign != NULL) {
        !           477:                        readlink(filename, filename, sizeof(filename));
        !           478:                        fprintf(stderr, "Using sign key %s\n",
        !           479:                            filename);
        !           480:                } else if (pkey_host != NULL) {
        !           481:                        pkey_sign = pkey_host;
        !           482:                        fprintf(stderr, "Using host key as sign key\n");
        !           483:                }
        !           484:        }
        !           485: 
        !           486:        /*
        !           487:         * Create new encrypted GQ server keys file if requested;
        !           488:         * otherwise, look for an exisiting file. If found, fetch the
        !           489:         * public key for the certificate.
        !           490:         */
        !           491:        if (gqkey)
        !           492:                pkey_gqkey = gen_gqkey("gqkey");
        !           493:        if (pkey_gqkey == NULL) {
        !           494:                sprintf(filename, "ntpkey_gqkey_%s", groupname);
        !           495:                pkey_gqkey = readkey(filename, passwd1, &fstamp, NULL);
        !           496:                if (pkey_gqkey != NULL) {
        !           497:                        readlink(filename, filename, sizeof(filename));
        !           498:                        fprintf(stderr, "Using GQ parameters %s\n",
        !           499:                            filename);
        !           500:                }
        !           501:        }
        !           502:        if (pkey_gqkey != NULL)
        !           503:                grpkey = BN_bn2hex(pkey_gqkey->pkey.rsa->q);
        !           504: 
        !           505:        /*
        !           506:         * Write the nonencrypted GQ client parameters to the stdout
        !           507:         * stream. The parameter file is the server key file with the
        !           508:         * private key obscured.
        !           509:         */
        !           510:        if (pkey_gqkey != NULL && HAVE_OPT(ID_KEY)) {
        !           511:                RSA     *rsa;
        !           512: 
        !           513:                epoch = fstamp - JAN_1970;
        !           514:                sprintf(filename, "ntpkey_gqpar_%s.%u", groupname,
        !           515:                    fstamp);
        !           516:                fprintf(stderr, "Writing GQ parameters %s to stdout\n",
        !           517:                    filename);
        !           518:                fprintf(stdout, "# %s\n# %s\n", filename,
        !           519:                    ctime(&epoch));
        !           520:                rsa = pkey_gqkey->pkey.rsa;
        !           521:                BN_copy(rsa->p, BN_value_one());
        !           522:                BN_copy(rsa->q, BN_value_one());
        !           523:                pkey = EVP_PKEY_new();
        !           524:                EVP_PKEY_assign_RSA(pkey, rsa);
        !           525:                PEM_write_PrivateKey(stdout, pkey, NULL, NULL, 0, NULL,
        !           526:                    NULL);
        !           527:                fclose(stdout);
        !           528:                if (debug)
        !           529:                        RSA_print_fp(stderr, rsa, 0);
        !           530:        }
        !           531: 
        !           532:        /*
        !           533:         * Write the encrypted GQ server keys to the stdout stream.
        !           534:         */
        !           535:        if (pkey_gqkey != NULL && passwd2 != NULL) {
        !           536:                RSA     *rsa;
        !           537: 
        !           538:                sprintf(filename, "ntpkey_gqkey_%s.%u", groupname,
        !           539:                    fstamp);
        !           540:                fprintf(stderr, "Writing GQ keys %s to stdout\n",
        !           541:                    filename);
        !           542:                fprintf(stdout, "# %s\n# %s\n", filename,
        !           543:                    ctime(&epoch));
        !           544:                rsa = pkey_gqkey->pkey.rsa;
        !           545:                pkey = EVP_PKEY_new();
        !           546:                EVP_PKEY_assign_RSA(pkey, rsa);
        !           547:                PEM_write_PrivateKey(stdout, pkey,
        !           548:                    EVP_des_cbc(), NULL, 0, NULL, passwd2);
        !           549:                fclose(stdout);
        !           550:                if (debug)
        !           551:                        RSA_print_fp(stderr, rsa, 0);
        !           552:        }
        !           553: 
        !           554:        /*
        !           555:         * Create new encrypted IFF server keys file if requested;
        !           556:         * otherwise, look for existing file.
        !           557:         */
        !           558:        if (iffkey)
        !           559:                pkey_iffkey = gen_iffkey("iffkey");
        !           560:        if (pkey_iffkey == NULL) {
        !           561:                sprintf(filename, "ntpkey_iffkey_%s", groupname);
        !           562:                pkey_iffkey = readkey(filename, passwd1, &fstamp, NULL);
        !           563:                if (pkey_iffkey != NULL) {
        !           564:                        readlink(filename, filename, sizeof(filename));
        !           565:                        fprintf(stderr, "Using IFF keys %s\n",
        !           566:                            filename);
        !           567:                }
        !           568:        }
        !           569: 
        !           570:        /*
        !           571:         * Write the nonencrypted IFF client parameters to the stdout
        !           572:         * stream. The parameter file is the server key file with the
        !           573:         * private key obscured.
        !           574:         */
        !           575:        if (pkey_iffkey != NULL && HAVE_OPT(ID_KEY)) {
        !           576:                DSA     *dsa;
        !           577: 
        !           578:                epoch = fstamp - JAN_1970;
        !           579:                sprintf(filename, "ntpkey_iffpar_%s.%u", groupname,
        !           580:                    fstamp);
        !           581:                fprintf(stderr, "Writing IFF parameters %s to stdout\n",
        !           582:                    filename);
        !           583:                fprintf(stdout, "# %s\n# %s\n", filename,
        !           584:                    ctime(&epoch));
        !           585:                dsa = pkey_iffkey->pkey.dsa;
        !           586:                BN_copy(dsa->priv_key, BN_value_one());
        !           587:                pkey = EVP_PKEY_new();
        !           588:                EVP_PKEY_assign_DSA(pkey, dsa);
        !           589:                PEM_write_PrivateKey(stdout, pkey, NULL, NULL, 0, NULL,
        !           590:                    NULL);
        !           591:                fclose(stdout);
        !           592:                if (debug)
        !           593:                        DSA_print_fp(stderr, dsa, 0);
        !           594:        }
        !           595: 
        !           596:        /*
        !           597:         * Write the encrypted IFF server keys to the stdout stream.
        !           598:         */
        !           599:        if (pkey_iffkey != NULL && passwd2 != NULL) {
        !           600:                DSA     *dsa;
        !           601: 
        !           602:                epoch = fstamp - JAN_1970;
        !           603:                sprintf(filename, "ntpkey_iffkey_%s.%u", groupname,
        !           604:                    fstamp);
        !           605:                fprintf(stderr, "Writing IFF keys %s to stdout\n",
        !           606:                    filename);
        !           607:                fprintf(stdout, "# %s\n# %s\n", filename,
        !           608:                    ctime(&epoch));
        !           609:                dsa = pkey_iffkey->pkey.dsa;
        !           610:                pkey = EVP_PKEY_new();
        !           611:                EVP_PKEY_assign_DSA(pkey, dsa);
        !           612:                PEM_write_PrivateKey(stdout, pkey, EVP_des_cbc(), NULL,
        !           613:                    0, NULL, passwd2);
        !           614:                fclose(stdout);
        !           615:                if (debug)
        !           616:                        DSA_print_fp(stderr, dsa, 0);
        !           617:        }
        !           618: 
        !           619:        /*
        !           620:         * Create new encrypted MV trusted-authority keys file if
        !           621:         * requested; otherwise, look for existing keys file.
        !           622:         */
        !           623:        if (mvkey)
        !           624:                pkey_mvkey = gen_mvkey("mv", pkey_mvpar);
        !           625:        if (pkey_mvkey == NULL) {
        !           626:                sprintf(filename, "ntpkey_mvta_%s", groupname);
        !           627:                pkey_mvkey = readkey(filename, passwd1, &fstamp,
        !           628:                   pkey_mvpar);
        !           629:                if (pkey_mvkey != NULL) {
        !           630:                        readlink(filename, filename, sizeof(filename));
        !           631:                        fprintf(stderr, "Using MV keys %s\n",
        !           632:                            filename);
        !           633:                }
        !           634:        }
        !           635: 
        !           636:        /*
        !           637:         * Write the nonencrypted MV client parameters to the stdout
        !           638:         * stream. For the moment, we always use the client parameters
        !           639:         * associated with client key 1.
        !           640:         */
        !           641:        if (pkey_mvkey != NULL && HAVE_OPT(ID_KEY)) {
        !           642:                epoch = fstamp - JAN_1970;
        !           643:                sprintf(filename, "ntpkey_mvpar_%s.%u", groupname,
        !           644:                    fstamp);
        !           645:                fprintf(stderr, "Writing MV parameters %s to stdout\n",
        !           646:                    filename);
        !           647:                fprintf(stdout, "# %s\n# %s\n", filename,
        !           648:                    ctime(&epoch));
        !           649:                pkey = pkey_mvpar[2];
        !           650:                PEM_write_PrivateKey(stdout, pkey, NULL, NULL, 0, NULL,
        !           651:                    NULL);
        !           652:                fclose(stdout);
        !           653:                if (debug)
        !           654:                        DSA_print_fp(stderr, pkey->pkey.dsa, 0);
        !           655:        }
        !           656: 
        !           657:        /*
        !           658:         * Write the encrypted MV server keys to the stdout stream.
        !           659:         */
        !           660:        if (pkey_mvkey != NULL && passwd2 != NULL) {
        !           661:                epoch = fstamp - JAN_1970;
        !           662:                sprintf(filename, "ntpkey_mvkey_%s.%u", groupname,
        !           663:                    fstamp);
        !           664:                fprintf(stderr, "Writing MV keys %s to stdout\n",
        !           665:                    filename);
        !           666:                fprintf(stdout, "# %s\n# %s\n", filename,
        !           667:                    ctime(&epoch));
        !           668:                pkey = pkey_mvpar[1];
        !           669:                PEM_write_PrivateKey(stdout, pkey, EVP_des_cbc(), NULL,
        !           670:                    0, NULL, passwd2);
        !           671:                fclose(stdout);
        !           672:                if (debug)
        !           673:                        DSA_print_fp(stderr, pkey->pkey.dsa, 0);
        !           674:        }
        !           675: 
        !           676:        /*
        !           677:         * Don't generate a certificate if no host keys or extracting
        !           678:         * encrypted or nonencrypted keys to the standard output stream.
        !           679:         */
        !           680:        if (pkey_host == NULL || HAVE_OPT(ID_KEY) || passwd2 != NULL)
        !           681:                exit (0);
        !           682: 
        !           683:        /*
        !           684:         * Decode the digest/signature scheme. If trusted, set the
        !           685:         * subject and issuer names to the group name; if not set both
        !           686:         * to the host name.
        !           687:         */
        !           688:        ectx = EVP_get_digestbyname(scheme);
        !           689:        if (ectx == NULL) {
        !           690:                fprintf(stderr,
        !           691:                    "Invalid digest/signature combination %s\n",
        !           692:                    scheme);
        !           693:                        exit (-1);
        !           694:        }
        !           695:        if (exten == NULL)
        !           696:                x509(pkey_sign, ectx, grpkey, exten, hostname);
        !           697:        else
        !           698:                x509(pkey_sign, ectx, grpkey, exten, groupname);
        !           699: #endif /* OPENSSL */
        !           700:        exit (0);
        !           701: }
        !           702: 
        !           703: 
        !           704: /*
        !           705:  * Generate semi-random MD5 keys compatible with NTPv3 and NTPv4. Also,
        !           706:  * if OpenSSL is around, generate random SHA1 keys compatible with
        !           707:  * symmetric key cryptography.
        !           708:  */
        !           709: int
        !           710: gen_md5(
        !           711:        char    *id             /* file name id */
        !           712:        )
        !           713: {
        !           714:        u_char  md5key[MD5SIZE + 1];    /* MD5 key */
        !           715:        FILE    *str;
        !           716:        int     i, j;
        !           717: #ifdef OPENSSL
        !           718:        u_char  keystr[MD5SIZE];
        !           719:        u_char  hexstr[2 * MD5SIZE + 1];
        !           720:        u_char  hex[] = "0123456789abcdef";
        !           721: #endif /* OPENSSL */
        !           722: 
        !           723:        str = fheader("MD5key", id, groupname);
        !           724:        ntp_srandom((u_long)epoch);
        !           725:        for (i = 1; i <= MD5KEYS; i++) {
        !           726:                for (j = 0; j < MD5SIZE; j++) {
        !           727:                        int temp;
        !           728: 
        !           729:                        while (1) {
        !           730:                                temp = ntp_random() & 0xff;
        !           731:                                if (temp == '#')
        !           732:                                        continue;
        !           733: 
        !           734:                                if (temp > 0x20 && temp < 0x7f)
        !           735:                                        break;
        !           736:                        }
        !           737:                        md5key[j] = (u_char)temp;
        !           738:                }
        !           739:                md5key[j] = '\0';
        !           740:                fprintf(str, "%2d MD5 %s  # MD5 key\n", i,
        !           741:                    md5key);
        !           742:        }
        !           743: #ifdef OPENSSL
        !           744:        for (i = 1; i <= MD5KEYS; i++) {
        !           745:                RAND_bytes(keystr, 20);
        !           746:                for (j = 0; j < MD5SIZE; j++) {
        !           747:                        hexstr[2 * j] = hex[keystr[j] >> 4];
        !           748:                        hexstr[2 * j + 1] = hex[keystr[j] & 0xf];
        !           749:                }
        !           750:                hexstr[2 * MD5SIZE] = '\0';
        !           751:                fprintf(str, "%2d SHA1 %s  # SHA1 key\n", i + MD5KEYS,
        !           752:                    hexstr);
        !           753:        }
        !           754: #endif /* OPENSSL */
        !           755:        fclose(str);
        !           756:        return (1);
        !           757: }
        !           758: 
        !           759: 
        !           760: #ifdef OPENSSL
        !           761: /*
        !           762:  * readkey - load cryptographic parameters and keys
        !           763:  *
        !           764:  * This routine loads a PEM-encoded file of given name and password and
        !           765:  * extracts the filestamp from the file name. It returns a pointer to
        !           766:  * the first key if valid, NULL if not.
        !           767:  */
        !           768: EVP_PKEY *                     /* public/private key pair */
        !           769: readkey(
        !           770:        char    *cp,            /* file name */
        !           771:        char    *passwd,        /* password */
        !           772:        u_int   *estamp,        /* file stamp */
        !           773:        EVP_PKEY **evpars       /* parameter list pointer */
        !           774:        )
        !           775: {
        !           776:        FILE    *str;           /* file handle */
        !           777:        EVP_PKEY *pkey = NULL;  /* public/private key */
        !           778:        u_int   gstamp;         /* filestamp */
        !           779:        char    linkname[MAXFILENAME]; /* filestamp buffer) */
        !           780:        EVP_PKEY *parkey;
        !           781:        char    *ptr;
        !           782:        int     i;
        !           783: 
        !           784:        /*
        !           785:         * Open the key file.
        !           786:         */
        !           787:        str = fopen(cp, "r");
        !           788:        if (str == NULL)
        !           789:                return (NULL);
        !           790: 
        !           791:        /*
        !           792:         * Read the filestamp, which is contained in the first line.
        !           793:         */
        !           794:        if ((ptr = fgets(linkname, MAXFILENAME, str)) == NULL) {
        !           795:                fprintf(stderr, "Empty key file %s\n", cp);
        !           796:                fclose(str);
        !           797:                return (NULL);
        !           798:        }
        !           799:        if ((ptr = strrchr(ptr, '.')) == NULL) {
        !           800:                fprintf(stderr, "No filestamp found in %s\n", cp);
        !           801:                fclose(str);
        !           802:                return (NULL);
        !           803:        }
        !           804:        if (sscanf(++ptr, "%u", &gstamp) != 1) {
        !           805:                fprintf(stderr, "Invalid filestamp found in %s\n", cp);
        !           806:                fclose(str);
        !           807:                return (NULL);
        !           808:        }
        !           809: 
        !           810:        /*
        !           811:         * Read and decrypt PEM-encoded private keys. The first one
        !           812:         * found is returned. If others are expected, add them to the
        !           813:         * parameter list.
        !           814:         */
        !           815:        for (i = 0; i <= MVMAX - 1;) {
        !           816:                parkey = PEM_read_PrivateKey(str, NULL, NULL, passwd);
        !           817:                if (evpars != NULL) {
        !           818:                        evpars[i++] = parkey;
        !           819:                        evpars[i] = NULL;
        !           820:                }
        !           821:                if (parkey == NULL)
        !           822:                        break;
        !           823: 
        !           824:                if (pkey == NULL)
        !           825:                        pkey = parkey;
        !           826:                if (debug) {
        !           827:                        if (parkey->type == EVP_PKEY_DSA)
        !           828:                                DSA_print_fp(stderr, parkey->pkey.dsa,
        !           829:                                    0);
        !           830:                        else if (parkey->type == EVP_PKEY_RSA)
        !           831:                                RSA_print_fp(stderr, parkey->pkey.rsa,
        !           832:                                    0);
        !           833:                }
        !           834:        }
        !           835:        fclose(str);
        !           836:        if (pkey == NULL) {
        !           837:                fprintf(stderr, "Corrupt file %s or wrong key %s\n%s\n",
        !           838:                    cp, passwd, ERR_error_string(ERR_get_error(),
        !           839:                    NULL));
        !           840:                exit (-1);
        !           841:        }
        !           842:        *estamp = gstamp;
        !           843:        return (pkey);
        !           844: }
        !           845: 
        !           846: 
        !           847: /*
        !           848:  * Generate RSA public/private key pair
        !           849:  */
        !           850: EVP_PKEY *                     /* public/private key pair */
        !           851: gen_rsa(
        !           852:        char    *id             /* file name id */
        !           853:        )
        !           854: {
        !           855:        EVP_PKEY *pkey;         /* private key */
        !           856:        RSA     *rsa;           /* RSA parameters and key pair */
        !           857:        FILE    *str;
        !           858: 
        !           859:        fprintf(stderr, "Generating RSA keys (%d bits)...\n", modulus);
        !           860:        rsa = RSA_generate_key(modulus, 3, cb, "RSA");
        !           861:        fprintf(stderr, "\n");
        !           862:        if (rsa == NULL) {
        !           863:                fprintf(stderr, "RSA generate keys fails\n%s\n",
        !           864:                    ERR_error_string(ERR_get_error(), NULL));
        !           865:                return (NULL);
        !           866:        }
        !           867: 
        !           868:        /*
        !           869:         * For signature encryption it is not necessary that the RSA
        !           870:         * parameters be strictly groomed and once in a while the
        !           871:         * modulus turns out to be non-prime. Just for grins, we check
        !           872:         * the primality.
        !           873:         */
        !           874:        if (!RSA_check_key(rsa)) {
        !           875:                fprintf(stderr, "Invalid RSA key\n%s\n",
        !           876:                    ERR_error_string(ERR_get_error(), NULL));
        !           877:                RSA_free(rsa);
        !           878:                return (NULL);
        !           879:        }
        !           880: 
        !           881:        /*
        !           882:         * Write the RSA parameters and keys as a RSA private key
        !           883:         * encoded in PEM.
        !           884:         */
        !           885:        if (strcmp(id, "sign") == 0)
        !           886:                str = fheader("RSAsign", id, hostname);
        !           887:        else
        !           888:                str = fheader("RSAhost", id, hostname);
        !           889:        pkey = EVP_PKEY_new();
        !           890:        EVP_PKEY_assign_RSA(pkey, rsa);
        !           891:        PEM_write_PrivateKey(str, pkey, EVP_des_cbc(), NULL, 0, NULL,
        !           892:            passwd1);
        !           893:        fclose(str);
        !           894:        if (debug)
        !           895:                RSA_print_fp(stderr, rsa, 0);
        !           896:        return (pkey);
        !           897: }
        !           898: 
        !           899:  
        !           900: /*
        !           901:  * Generate DSA public/private key pair
        !           902:  */
        !           903: EVP_PKEY *                     /* public/private key pair */
        !           904: gen_dsa(
        !           905:        char    *id             /* file name id */
        !           906:        )
        !           907: {
        !           908:        EVP_PKEY *pkey;         /* private key */
        !           909:        DSA     *dsa;           /* DSA parameters */
        !           910:        u_char  seed[20];       /* seed for parameters */
        !           911:        FILE    *str;
        !           912: 
        !           913:        /*
        !           914:         * Generate DSA parameters.
        !           915:         */
        !           916:        fprintf(stderr,
        !           917:            "Generating DSA parameters (%d bits)...\n", modulus);
        !           918:        RAND_bytes(seed, sizeof(seed));
        !           919:        dsa = DSA_generate_parameters(modulus, seed, sizeof(seed), NULL,
        !           920:            NULL, cb, "DSA");
        !           921:        fprintf(stderr, "\n");
        !           922:        if (dsa == NULL) {
        !           923:                fprintf(stderr, "DSA generate parameters fails\n%s\n",
        !           924:                    ERR_error_string(ERR_get_error(), NULL));
        !           925:                return (NULL);
        !           926:        }
        !           927: 
        !           928:        /*
        !           929:         * Generate DSA keys.
        !           930:         */
        !           931:        fprintf(stderr, "Generating DSA keys (%d bits)...\n", modulus);
        !           932:        if (!DSA_generate_key(dsa)) {
        !           933:                fprintf(stderr, "DSA generate keys fails\n%s\n",
        !           934:                    ERR_error_string(ERR_get_error(), NULL));
        !           935:                DSA_free(dsa);
        !           936:                return (NULL);
        !           937:        }
        !           938: 
        !           939:        /*
        !           940:         * Write the DSA parameters and keys as a DSA private key
        !           941:         * encoded in PEM.
        !           942:         */
        !           943:        str = fheader("DSAsign", id, hostname);
        !           944:        pkey = EVP_PKEY_new();
        !           945:        EVP_PKEY_assign_DSA(pkey, dsa);
        !           946:        PEM_write_PrivateKey(str, pkey, EVP_des_cbc(), NULL, 0, NULL,
        !           947:            passwd1);
        !           948:        fclose(str);
        !           949:        if (debug)
        !           950:                DSA_print_fp(stderr, dsa, 0);
        !           951:        return (pkey);
        !           952: }
        !           953: 
        !           954: 
        !           955: /*
        !           956:  ***********************************************************************
        !           957:  *                                                                    *
        !           958:  * The following routines implement the Schnorr (IFF) identity scheme  *
        !           959:  *                                                                    *
        !           960:  ***********************************************************************
        !           961:  *
        !           962:  * The Schnorr (IFF) identity scheme is intended for use when
        !           963:  * certificates are generated by some other trusted certificate
        !           964:  * authority and the certificate cannot be used to convey public
        !           965:  * parameters. There are two kinds of files: encrypted server files that
        !           966:  * contain private and public values and nonencrypted client files that
        !           967:  * contain only public values. New generations of server files must be
        !           968:  * securely transmitted to all servers of the group; client files can be
        !           969:  * distributed by any means. The scheme is self contained and
        !           970:  * independent of new generations of host keys, sign keys and
        !           971:  * certificates.
        !           972:  *
        !           973:  * The IFF values hide in a DSA cuckoo structure which uses the same
        !           974:  * parameters. The values are used by an identity scheme based on DSA
        !           975:  * cryptography and described in Stimson p. 285. The p is a 512-bit
        !           976:  * prime, g a generator of Zp* and q a 160-bit prime that divides p - 1
        !           977:  * and is a qth root of 1 mod p; that is, g^q = 1 mod p. The TA rolls a
        !           978:  * private random group key b (0 < b < q) and public key v = g^b, then
        !           979:  * sends (p, q, g, b) to the servers and (p, q, g, v) to the clients.
        !           980:  * Alice challenges Bob to confirm identity using the protocol described
        !           981:  * below.
        !           982:  *
        !           983:  * How it works
        !           984:  *
        !           985:  * The scheme goes like this. Both Alice and Bob have the public primes
        !           986:  * p, q and generator g. The TA gives private key b to Bob and public
        !           987:  * key v to Alice.
        !           988:  *
        !           989:  * Alice rolls new random challenge r (o < r < q) and sends to Bob in
        !           990:  * the IFF request message. Bob rolls new random k (0 < k < q), then
        !           991:  * computes y = k + b r mod q and x = g^k mod p and sends (y, hash(x))
        !           992:  * to Alice in the response message. Besides making the response
        !           993:  * shorter, the hash makes it effectivey impossible for an intruder to
        !           994:  * solve for b by observing a number of these messages.
        !           995:  * 
        !           996:  * Alice receives the response and computes g^y v^r mod p. After a bit
        !           997:  * of algebra, this simplifies to g^k. If the hash of this result
        !           998:  * matches hash(x), Alice knows that Bob has the group key b. The signed
        !           999:  * response binds this knowledge to Bob's private key and the public key
        !          1000:  * previously received in his certificate.
        !          1001:  */
        !          1002: /*
        !          1003:  * Generate Schnorr (IFF) keys.
        !          1004:  */
        !          1005: EVP_PKEY *                     /* DSA cuckoo nest */
        !          1006: gen_iffkey(
        !          1007:        char    *id             /* file name id */
        !          1008:        )
        !          1009: {
        !          1010:        EVP_PKEY *pkey;         /* private key */
        !          1011:        DSA     *dsa;           /* DSA parameters */
        !          1012:        u_char  seed[20];       /* seed for parameters */
        !          1013:        BN_CTX  *ctx;           /* BN working space */
        !          1014:        BIGNUM  *b, *r, *k, *u, *v, *w; /* BN temp */
        !          1015:        FILE    *str;
        !          1016:        u_int   temp;
        !          1017: 
        !          1018:        /*
        !          1019:         * Generate DSA parameters for use as IFF parameters.
        !          1020:         */
        !          1021:        fprintf(stderr, "Generating IFF keys (%d bits)...\n",
        !          1022:            modulus2);
        !          1023:        RAND_bytes(seed, sizeof(seed));
        !          1024:        dsa = DSA_generate_parameters(modulus2, seed, sizeof(seed), NULL,
        !          1025:            NULL, cb, "IFF");
        !          1026:        fprintf(stderr, "\n");
        !          1027:        if (dsa == NULL) {
        !          1028:                fprintf(stderr, "DSA generate parameters fails\n%s\n",
        !          1029:                    ERR_error_string(ERR_get_error(), NULL));
        !          1030:                return (NULL);;
        !          1031:        }
        !          1032: 
        !          1033:        /*
        !          1034:         * Generate the private and public keys. The DSA parameters and
        !          1035:         * private key are distributed to the servers, while all except
        !          1036:         * the private key are distributed to the clients.
        !          1037:         */
        !          1038:        b = BN_new(); r = BN_new(); k = BN_new();
        !          1039:        u = BN_new(); v = BN_new(); w = BN_new(); ctx = BN_CTX_new();
        !          1040:        BN_rand(b, BN_num_bits(dsa->q), -1, 0); /* a */
        !          1041:        BN_mod(b, b, dsa->q, ctx);
        !          1042:        BN_sub(v, dsa->q, b);
        !          1043:        BN_mod_exp(v, dsa->g, v, dsa->p, ctx); /* g^(q - b) mod p */
        !          1044:        BN_mod_exp(u, dsa->g, b, dsa->p, ctx);  /* g^b mod p */
        !          1045:        BN_mod_mul(u, u, v, dsa->p, ctx);
        !          1046:        temp = BN_is_one(u);
        !          1047:        fprintf(stderr,
        !          1048:            "Confirm g^(q - b) g^b = 1 mod p: %s\n", temp == 1 ?
        !          1049:            "yes" : "no");
        !          1050:        if (!temp) {
        !          1051:                BN_free(b); BN_free(r); BN_free(k);
        !          1052:                BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx);
        !          1053:                return (NULL);
        !          1054:        }
        !          1055:        dsa->priv_key = BN_dup(b);              /* private key */
        !          1056:        dsa->pub_key = BN_dup(v);               /* public key */
        !          1057: 
        !          1058:        /*
        !          1059:         * Here is a trial round of the protocol. First, Alice rolls
        !          1060:         * random nonce r mod q and sends it to Bob. She needs only
        !          1061:         * q from parameters.
        !          1062:         */
        !          1063:        BN_rand(r, BN_num_bits(dsa->q), -1, 0); /* r */
        !          1064:        BN_mod(r, r, dsa->q, ctx);
        !          1065: 
        !          1066:        /*
        !          1067:         * Bob rolls random nonce k mod q, computes y = k + b r mod q
        !          1068:         * and x = g^k mod p, then sends (y, x) to Alice. He needs
        !          1069:         * p, q and b from parameters and r from Alice.
        !          1070:         */
        !          1071:        BN_rand(k, BN_num_bits(dsa->q), -1, 0); /* k, 0 < k < q  */
        !          1072:        BN_mod(k, k, dsa->q, ctx);
        !          1073:        BN_mod_mul(v, dsa->priv_key, r, dsa->q, ctx); /* b r mod q */
        !          1074:        BN_add(v, v, k);
        !          1075:        BN_mod(v, v, dsa->q, ctx);              /* y = k + b r mod q */
        !          1076:        BN_mod_exp(u, dsa->g, k, dsa->p, ctx);  /* x = g^k mod p */
        !          1077: 
        !          1078:        /*
        !          1079:         * Alice verifies x = g^y v^r to confirm that Bob has group key
        !          1080:         * b. She needs p, q, g from parameters, (y, x) from Bob and the
        !          1081:         * original r. We omit the detail here thatt only the hash of y
        !          1082:         * is sent.
        !          1083:         */
        !          1084:        BN_mod_exp(v, dsa->g, v, dsa->p, ctx); /* g^y mod p */
        !          1085:        BN_mod_exp(w, dsa->pub_key, r, dsa->p, ctx); /* v^r */
        !          1086:        BN_mod_mul(v, w, v, dsa->p, ctx);       /* product mod p */
        !          1087:        temp = BN_cmp(u, v);
        !          1088:        fprintf(stderr,
        !          1089:            "Confirm g^k = g^(k + b r) g^(q - b) r: %s\n", temp ==
        !          1090:            0 ? "yes" : "no");
        !          1091:        BN_free(b); BN_free(r); BN_free(k);
        !          1092:        BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx);
        !          1093:        if (temp != 0) {
        !          1094:                DSA_free(dsa);
        !          1095:                return (NULL);
        !          1096:        }
        !          1097: 
        !          1098:        /*
        !          1099:         * Write the IFF keys as an encrypted DSA private key encoded in
        !          1100:         * PEM.
        !          1101:         *
        !          1102:         * p    modulus p
        !          1103:         * q    modulus q
        !          1104:         * g    generator g
        !          1105:         * priv_key b
        !          1106:         * public_key v
        !          1107:         * kinv not used
        !          1108:         * r    not used
        !          1109:         */
        !          1110:        str = fheader("IFFkey", id, groupname);
        !          1111:        pkey = EVP_PKEY_new();
        !          1112:        EVP_PKEY_assign_DSA(pkey, dsa);
        !          1113:        PEM_write_PrivateKey(str, pkey, EVP_des_cbc(), NULL, 0, NULL,
        !          1114:            passwd1);
        !          1115:        fclose(str);
        !          1116:        if (debug)
        !          1117:                DSA_print_fp(stderr, dsa, 0);
        !          1118:        return (pkey);
        !          1119: }
        !          1120: 
        !          1121: 
        !          1122: /*
        !          1123:  ***********************************************************************
        !          1124:  *                                                                    *
        !          1125:  * The following routines implement the Guillou-Quisquater (GQ)        *
        !          1126:  * identity scheme                                                     *
        !          1127:  *                                                                    *
        !          1128:  ***********************************************************************
        !          1129:  *
        !          1130:  * The Guillou-Quisquater (GQ) identity scheme is intended for use when
        !          1131:  * the certificate can be used to convey public parameters. The scheme
        !          1132:  * uses a X509v3 certificate extension field do convey the public key of
        !          1133:  * a private key known only to servers. There are two kinds of files:
        !          1134:  * encrypted server files that contain private and public values and
        !          1135:  * nonencrypted client files that contain only public values. New
        !          1136:  * generations of server files must be securely transmitted to all
        !          1137:  * servers of the group; client files can be distributed by any means.
        !          1138:  * The scheme is self contained and independent of new generations of
        !          1139:  * host keys and sign keys. The scheme is self contained and independent
        !          1140:  * of new generations of host keys and sign keys.
        !          1141:  *
        !          1142:  * The GQ parameters hide in a RSA cuckoo structure which uses the same
        !          1143:  * parameters. The values are used by an identity scheme based on RSA
        !          1144:  * cryptography and described in Stimson p. 300 (with errors). The 512-
        !          1145:  * bit public modulus is n = p q, where p and q are secret large primes.
        !          1146:  * The TA rolls private random group key b as RSA exponent. These values
        !          1147:  * are known to all group members.
        !          1148:  *
        !          1149:  * When rolling new certificates, a server recomputes the private and
        !          1150:  * public keys. The private key u is a random roll, while the public key
        !          1151:  * is the inverse obscured by the group key v = (u^-1)^b. These values
        !          1152:  * replace the private and public keys normally generated by the RSA
        !          1153:  * scheme. Alice challenges Bob to confirm identity using the protocol
        !          1154:  * described below.
        !          1155:  *
        !          1156:  * How it works
        !          1157:  *
        !          1158:  * The scheme goes like this. Both Alice and Bob have the same modulus n
        !          1159:  * and some random b as the group key. These values are computed and
        !          1160:  * distributed in advance via secret means, although only the group key
        !          1161:  * b is truly secret. Each has a private random private key u and public
        !          1162:  * key (u^-1)^b, although not necessarily the same ones. Bob and Alice
        !          1163:  * can regenerate the key pair from time to time without affecting
        !          1164:  * operations. The public key is conveyed on the certificate in an
        !          1165:  * extension field; the private key is never revealed.
        !          1166:  *
        !          1167:  * Alice rolls new random challenge r and sends to Bob in the GQ
        !          1168:  * request message. Bob rolls new random k, then computes y = k u^r mod
        !          1169:  * n and x = k^b mod n and sends (y, hash(x)) to Alice in the response
        !          1170:  * message. Besides making the response shorter, the hash makes it
        !          1171:  * effectivey impossible for an intruder to solve for b by observing
        !          1172:  * a number of these messages.
        !          1173:  * 
        !          1174:  * Alice receives the response and computes y^b v^r mod n. After a bit
        !          1175:  * of algebra, this simplifies to k^b. If the hash of this result
        !          1176:  * matches hash(x), Alice knows that Bob has the group key b. The signed
        !          1177:  * response binds this knowledge to Bob's private key and the public key
        !          1178:  * previously received in his certificate.
        !          1179:  */
        !          1180: /*
        !          1181:  * Generate Guillou-Quisquater (GQ) parameters file.
        !          1182:  */
        !          1183: EVP_PKEY *                     /* RSA cuckoo nest */
        !          1184: gen_gqkey(
        !          1185:        char    *id             /* file name id */
        !          1186:        )
        !          1187: {
        !          1188:        EVP_PKEY *pkey;         /* private key */
        !          1189:        RSA     *rsa;           /* RSA parameters */
        !          1190:        BN_CTX  *ctx;           /* BN working space */
        !          1191:        BIGNUM  *u, *v, *g, *k, *r, *y; /* BN temps */
        !          1192:        FILE    *str;
        !          1193:        u_int   temp;
        !          1194: 
        !          1195:        /*
        !          1196:         * Generate RSA parameters for use as GQ parameters.
        !          1197:         */
        !          1198:        fprintf(stderr,
        !          1199:            "Generating GQ parameters (%d bits)...\n",
        !          1200:             modulus2);
        !          1201:        rsa = RSA_generate_key(modulus2, 3, cb, "GQ");
        !          1202:        fprintf(stderr, "\n");
        !          1203:        if (rsa == NULL) {
        !          1204:                fprintf(stderr, "RSA generate keys fails\n%s\n",
        !          1205:                    ERR_error_string(ERR_get_error(), NULL));
        !          1206:                return (NULL);
        !          1207:        }
        !          1208:        ctx = BN_CTX_new(); u = BN_new(); v = BN_new();
        !          1209:        g = BN_new(); k = BN_new(); r = BN_new(); y = BN_new();
        !          1210: 
        !          1211:        /*
        !          1212:         * Generate the group key b, which is saved in the e member of
        !          1213:         * the RSA structure. The group key is transmitted to each group
        !          1214:         * member encrypted by the member private key.
        !          1215:         */
        !          1216:        ctx = BN_CTX_new();
        !          1217:        BN_rand(rsa->e, BN_num_bits(rsa->n), -1, 0); /* b */
        !          1218:        BN_mod(rsa->e, rsa->e, rsa->n, ctx);
        !          1219: 
        !          1220:        /*
        !          1221:         * When generating his certificate, Bob rolls random private key
        !          1222:         * u, then computes inverse v = u^-1. 
        !          1223:         */
        !          1224:        BN_rand(u, BN_num_bits(rsa->n), -1, 0); /* u */
        !          1225:        BN_mod(u, u, rsa->n, ctx);
        !          1226:        BN_mod_inverse(v, u, rsa->n, ctx);      /* u^-1 mod n */
        !          1227:        BN_mod_mul(k, v, u, rsa->n, ctx);
        !          1228: 
        !          1229:        /*
        !          1230:         * Bob computes public key v = (u^-1)^b, which is saved in an
        !          1231:         * extension field on his certificate. We check that u^b v =
        !          1232:         * 1 mod n.
        !          1233:         */
        !          1234:        BN_mod_exp(v, v, rsa->e, rsa->n, ctx);
        !          1235:        BN_mod_exp(g, u, rsa->e, rsa->n, ctx); /* u^b */
        !          1236:        BN_mod_mul(g, g, v, rsa->n, ctx); /* u^b (u^-1)^b */
        !          1237:        temp = BN_is_one(g);
        !          1238:        fprintf(stderr,
        !          1239:            "Confirm u^b (u^-1)^b = 1 mod n: %s\n", temp ? "yes" :
        !          1240:            "no");
        !          1241:        if (!temp) {
        !          1242:                BN_free(u); BN_free(v);
        !          1243:                BN_free(g); BN_free(k); BN_free(r); BN_free(y);
        !          1244:                BN_CTX_free(ctx);
        !          1245:                RSA_free(rsa);
        !          1246:                return (NULL);
        !          1247:        }
        !          1248:        BN_copy(rsa->p, u);                     /* private key */
        !          1249:        BN_copy(rsa->q, v);                     /* public key */
        !          1250: 
        !          1251:        /*
        !          1252:         * Here is a trial run of the protocol. First, Alice rolls
        !          1253:         * random nonce r mod n and sends it to Bob. She needs only n
        !          1254:         * from parameters.
        !          1255:         */
        !          1256:        BN_rand(r, BN_num_bits(rsa->n), -1, 0); /* r */
        !          1257:        BN_mod(r, r, rsa->n, ctx);
        !          1258: 
        !          1259:        /*
        !          1260:         * Bob rolls random nonce k mod n, computes y = k u^r mod n and
        !          1261:         * g = k^b mod n, then sends (y, g) to Alice. He needs n, u, b
        !          1262:         * from parameters and r from Alice. 
        !          1263:         */
        !          1264:        BN_rand(k, BN_num_bits(rsa->n), -1, 0); /* k */
        !          1265:        BN_mod(k, k, rsa->n, ctx);
        !          1266:        BN_mod_exp(y, rsa->p, r, rsa->n, ctx);  /* u^r mod n */
        !          1267:        BN_mod_mul(y, k, y, rsa->n, ctx);       /* y = k u^r mod n */
        !          1268:        BN_mod_exp(g, k, rsa->e, rsa->n, ctx);  /* g = k^b mod n */
        !          1269: 
        !          1270:        /*
        !          1271:         * Alice verifies g = v^r y^b mod n to confirm that Bob has
        !          1272:         * private key u. She needs n, g from parameters, public key v =
        !          1273:         * (u^-1)^b from the certificate, (y, g) from Bob and the
        !          1274:         * original r. We omit the detaul here that only the hash of g
        !          1275:         * is sent.
        !          1276:         */
        !          1277:        BN_mod_exp(v, rsa->q, r, rsa->n, ctx);  /* v^r mod n */
        !          1278:        BN_mod_exp(y, y, rsa->e, rsa->n, ctx); /* y^b mod n */
        !          1279:        BN_mod_mul(y, v, y, rsa->n, ctx);       /* v^r y^b mod n */
        !          1280:        temp = BN_cmp(y, g);
        !          1281:        fprintf(stderr, "Confirm g^k = v^r y^b mod n: %s\n", temp == 0 ?
        !          1282:            "yes" : "no");
        !          1283:        BN_CTX_free(ctx); BN_free(u); BN_free(v);
        !          1284:        BN_free(g); BN_free(k); BN_free(r); BN_free(y);
        !          1285:        if (temp != 0) {
        !          1286:                RSA_free(rsa);
        !          1287:                return (NULL);
        !          1288:        }
        !          1289: 
        !          1290:        /*
        !          1291:         * Write the GQ parameter file as an encrypted RSA private key
        !          1292:         * encoded in PEM.
        !          1293:         *
        !          1294:         * n    modulus n
        !          1295:         * e    group key b
        !          1296:         * d    not used
        !          1297:         * p    private key u
        !          1298:         * q    public key (u^-1)^b
        !          1299:         * dmp1 not used
        !          1300:         * dmq1 not used
        !          1301:         * iqmp not used
        !          1302:         */
        !          1303:        BN_copy(rsa->d, BN_value_one());
        !          1304:        BN_copy(rsa->dmp1, BN_value_one());
        !          1305:        BN_copy(rsa->dmq1, BN_value_one());
        !          1306:        BN_copy(rsa->iqmp, BN_value_one());
        !          1307:        str = fheader("GQkey", id, groupname);
        !          1308:        pkey = EVP_PKEY_new();
        !          1309:        EVP_PKEY_assign_RSA(pkey, rsa);
        !          1310:        PEM_write_PrivateKey(str, pkey, EVP_des_cbc(), NULL, 0, NULL,
        !          1311:            passwd1);
        !          1312:        fclose(str);
        !          1313:        if (debug)
        !          1314:                RSA_print_fp(stderr, rsa, 0);
        !          1315:        return (pkey);
        !          1316: }
        !          1317: 
        !          1318: 
        !          1319: /*
        !          1320:  ***********************************************************************
        !          1321:  *                                                                    *
        !          1322:  * The following routines implement the Mu-Varadharajan (MV) identity  *
        !          1323:  * scheme                                                              *
        !          1324:  *                                                                    *
        !          1325:  ***********************************************************************
        !          1326:  *
        !          1327:  * The Mu-Varadharajan (MV) cryptosystem was originally intended when
        !          1328:  * servers broadcast messages to clients, but clients never send
        !          1329:  * messages to servers. There is one encryption key for the server and a
        !          1330:  * separate decryption key for each client. It operated something like a
        !          1331:  * pay-per-view satellite broadcasting system where the session key is
        !          1332:  * encrypted by the broadcaster and the decryption keys are held in a
        !          1333:  * tamperproof set-top box.
        !          1334:  *
        !          1335:  * The MV parameters and private encryption key hide in a DSA cuckoo
        !          1336:  * structure which uses the same parameters, but generated in a
        !          1337:  * different way. The values are used in an encryption scheme similar to
        !          1338:  * El Gamal cryptography and a polynomial formed from the expansion of
        !          1339:  * product terms (x - x[j]), as described in Mu, Y., and V.
        !          1340:  * Varadharajan: Robust and Secure Broadcasting, Proc. Indocrypt 2001,
        !          1341:  * 223-231. The paper has significant errors and serious omissions.
        !          1342:  *
        !          1343:  * Let q be the product of n distinct primes s1[j] (j = 1...n), where
        !          1344:  * each s1[j] has m significant bits. Let p be a prime p = 2 * q + 1, so
        !          1345:  * that q and each s1[j] divide p - 1 and p has M = n * m + 1
        !          1346:  * significant bits. Let g be a generator of Zp; that is, gcd(g, p - 1)
        !          1347:  * = 1 and g^q = 1 mod p. We do modular arithmetic over Zq and then
        !          1348:  * project into Zp* as exponents of g. Sometimes we have to compute an
        !          1349:  * inverse b^-1 of random b in Zq, but for that purpose we require
        !          1350:  * gcd(b, q) = 1. We expect M to be in the 500-bit range and n
        !          1351:  * relatively small, like 30. These are the parameters of the scheme and
        !          1352:  * they are expensive to compute.
        !          1353:  *
        !          1354:  * We set up an instance of the scheme as follows. A set of random
        !          1355:  * values x[j] mod q (j = 1...n), are generated as the zeros of a
        !          1356:  * polynomial of order n. The product terms (x - x[j]) are expanded to
        !          1357:  * form coefficients a[i] mod q (i = 0...n) in powers of x. These are
        !          1358:  * used as exponents of the generator g mod p to generate the private
        !          1359:  * encryption key A. The pair (gbar, ghat) of public server keys and the
        !          1360:  * pairs (xbar[j], xhat[j]) (j = 1...n) of private client keys are used
        !          1361:  * to construct the decryption keys. The devil is in the details.
        !          1362:  *
        !          1363:  * This routine generates a private server encryption file including the
        !          1364:  * private encryption key E and partial decryption keys gbar and ghat.
        !          1365:  * It then generates public client decryption files including the public
        !          1366:  * keys xbar[j] and xhat[j] for each client j. The partial decryption
        !          1367:  * files are used to compute the inverse of E. These values are suitably
        !          1368:  * blinded so secrets are not revealed.
        !          1369:  *
        !          1370:  * The distinguishing characteristic of this scheme is the capability to
        !          1371:  * revoke keys. Included in the calculation of E, gbar and ghat is the
        !          1372:  * product s = prod(s1[j]) (j = 1...n) above. If the factor s1[j] is
        !          1373:  * subsequently removed from the product and E, gbar and ghat
        !          1374:  * recomputed, the jth client will no longer be able to compute E^-1 and
        !          1375:  * thus unable to decrypt the messageblock.
        !          1376:  *
        !          1377:  * How it works
        !          1378:  *
        !          1379:  * The scheme goes like this. Bob has the server values (p, E, q, gbar,
        !          1380:  * ghat) and Alice has the client values (p, xbar, xhat).
        !          1381:  *
        !          1382:  * Alice rolls new random nonce r mod p and sends to Bob in the MV
        !          1383:  * request message. Bob rolls random nonce k mod q, encrypts y = r E^k
        !          1384:  * mod p and sends (y, gbar^k, ghat^k) to Alice.
        !          1385:  * 
        !          1386:  * Alice receives the response and computes the inverse (E^k)^-1 from
        !          1387:  * the partial decryption keys gbar^k, ghat^k, xbar and xhat. She then
        !          1388:  * decrypts y and verifies it matches the original r. The signed
        !          1389:  * response binds this knowledge to Bob's private key and the public key
        !          1390:  * previously received in his certificate.
        !          1391:  */
        !          1392: EVP_PKEY *                     /* DSA cuckoo nest */
        !          1393: gen_mvkey(
        !          1394:        char    *id,            /* file name id */
        !          1395:        EVP_PKEY **evpars       /* parameter list pointer */
        !          1396:        )
        !          1397: {
        !          1398:        EVP_PKEY *pkey, *pkey1; /* private keys */
        !          1399:        DSA     *dsa, *dsa2, *sdsa; /* DSA parameters */
        !          1400:        BN_CTX  *ctx;           /* BN working space */
        !          1401:        BIGNUM  *a[MVMAX];      /* polynomial coefficient vector */
        !          1402:        BIGNUM  *g[MVMAX];      /* public key vector */
        !          1403:        BIGNUM  *s1[MVMAX];     /* private enabling keys */
        !          1404:        BIGNUM  *x[MVMAX];      /* polynomial zeros vector */
        !          1405:        BIGNUM  *xbar[MVMAX], *xhat[MVMAX]; /* private keys vector */
        !          1406:        BIGNUM  *b;             /* group key */
        !          1407:        BIGNUM  *b1;            /* inverse group key */
        !          1408:        BIGNUM  *s;             /* enabling key */
        !          1409:        BIGNUM  *biga;          /* master encryption key */
        !          1410:        BIGNUM  *bige;          /* session encryption key */
        !          1411:        BIGNUM  *gbar, *ghat;   /* public key */
        !          1412:        BIGNUM  *u, *v, *w;     /* BN scratch */
        !          1413:        int     i, j, n;
        !          1414:        FILE    *str;
        !          1415:        u_int   temp;
        !          1416: 
        !          1417:        /*
        !          1418:         * Generate MV parameters.
        !          1419:         *
        !          1420:         * The object is to generate a multiplicative group Zp* modulo a
        !          1421:         * prime p and a subset Zq mod q, where q is the product of n
        !          1422:         * distinct primes s1[j] (j = 1...n) and q divides p - 1. We
        !          1423:         * first generate n m-bit primes, where the product n m is in
        !          1424:         * the order of 512 bits. One or more of these may have to be
        !          1425:         * replaced later. As a practical matter, it is tough to find
        !          1426:         * more than 31 distinct primes for 512 bits or 61 primes for
        !          1427:         * 1024 bits. The latter can take several hundred iterations
        !          1428:         * and several minutes on a Sun Blade 1000.
        !          1429:         */
        !          1430:        n = nkeys;
        !          1431:        fprintf(stderr,
        !          1432:            "Generating MV parameters for %d keys (%d bits)...\n", n,
        !          1433:            modulus2 / n);
        !          1434:        ctx = BN_CTX_new(); u = BN_new(); v = BN_new(); w = BN_new();
        !          1435:        b = BN_new(); b1 = BN_new();
        !          1436:        dsa = DSA_new();
        !          1437:        dsa->p = BN_new(); dsa->q = BN_new(); dsa->g = BN_new();
        !          1438:        dsa->priv_key = BN_new(); dsa->pub_key = BN_new();
        !          1439:        temp = 0;
        !          1440:        for (j = 1; j <= n; j++) {
        !          1441:                s1[j] = BN_new();
        !          1442:                while (1) {
        !          1443:                        BN_generate_prime(s1[j], modulus2 / n, 0, NULL,
        !          1444:                            NULL, NULL, NULL);
        !          1445:                        for (i = 1; i < j; i++) {
        !          1446:                                if (BN_cmp(s1[i], s1[j]) == 0)
        !          1447:                                        break;
        !          1448:                        }
        !          1449:                        if (i == j)
        !          1450:                                break;
        !          1451:                        temp++;
        !          1452:                }
        !          1453:        }
        !          1454:        fprintf(stderr, "Birthday keys regenerated %d\n", temp);
        !          1455: 
        !          1456:        /*
        !          1457:         * Compute the modulus q as the product of the primes. Compute
        !          1458:         * the modulus p as 2 * q + 1 and test p for primality. If p
        !          1459:         * is composite, replace one of the primes with a new distinct
        !          1460:         * one and try again. Note that q will hardly be a secret since
        !          1461:         * we have to reveal p to servers, but not clients. However,
        !          1462:         * factoring q to find the primes should be adequately hard, as
        !          1463:         * this is the same problem considered hard in RSA. Question: is
        !          1464:         * it as hard to find n small prime factors totalling n bits as
        !          1465:         * it is to find two large prime factors totalling n bits?
        !          1466:         * Remember, the bad guy doesn't know n.
        !          1467:         */
        !          1468:        temp = 0;
        !          1469:        while (1) {
        !          1470:                BN_one(dsa->q);
        !          1471:                for (j = 1; j <= n; j++)
        !          1472:                        BN_mul(dsa->q, dsa->q, s1[j], ctx);
        !          1473:                BN_copy(dsa->p, dsa->q);
        !          1474:                BN_add(dsa->p, dsa->p, dsa->p);
        !          1475:                BN_add_word(dsa->p, 1);
        !          1476:                if (BN_is_prime(dsa->p, BN_prime_checks, NULL, ctx,
        !          1477:                    NULL))
        !          1478:                        break;
        !          1479: 
        !          1480:                temp++;
        !          1481:                j = temp % n + 1;
        !          1482:                while (1) {
        !          1483:                        BN_generate_prime(u, modulus2 / n, 0, 0, NULL,
        !          1484:                            NULL, NULL);
        !          1485:                        for (i = 1; i <= n; i++) {
        !          1486:                                if (BN_cmp(u, s1[i]) == 0)
        !          1487:                                        break;
        !          1488:                        }
        !          1489:                        if (i > n)
        !          1490:                                break;
        !          1491:                }
        !          1492:                BN_copy(s1[j], u);
        !          1493:        }
        !          1494:        fprintf(stderr, "Defective keys regenerated %d\n", temp);
        !          1495: 
        !          1496:        /*
        !          1497:         * Compute the generator g using a random roll such that
        !          1498:         * gcd(g, p - 1) = 1 and g^q = 1. This is a generator of p, not
        !          1499:         * q. This may take several iterations.
        !          1500:         */
        !          1501:        BN_copy(v, dsa->p);
        !          1502:        BN_sub_word(v, 1);
        !          1503:        while (1) {
        !          1504:                BN_rand(dsa->g, BN_num_bits(dsa->p) - 1, 0, 0);
        !          1505:                BN_mod(dsa->g, dsa->g, dsa->p, ctx);
        !          1506:                BN_gcd(u, dsa->g, v, ctx);
        !          1507:                if (!BN_is_one(u))
        !          1508:                        continue;
        !          1509: 
        !          1510:                BN_mod_exp(u, dsa->g, dsa->q, dsa->p, ctx);
        !          1511:                if (BN_is_one(u))
        !          1512:                        break;
        !          1513:        }
        !          1514: 
        !          1515:        /*
        !          1516:         * Setup is now complete. Roll random polynomial roots x[j]
        !          1517:         * (j = 1...n) for all j. While it may not be strictly
        !          1518:         * necessary, Make sure each root has no factors in common with
        !          1519:         * q.
        !          1520:         */
        !          1521:        fprintf(stderr,
        !          1522:            "Generating polynomial coefficients for %d roots (%d bits)\n",
        !          1523:            n, BN_num_bits(dsa->q)); 
        !          1524:        for (j = 1; j <= n; j++) {
        !          1525:                x[j] = BN_new();
        !          1526: 
        !          1527:                while (1) {
        !          1528:                        BN_rand(x[j], BN_num_bits(dsa->q), 0, 0);
        !          1529:                        BN_mod(x[j], x[j], dsa->q, ctx);
        !          1530:                        BN_gcd(u, x[j], dsa->q, ctx);
        !          1531:                        if (BN_is_one(u))
        !          1532:                                break;
        !          1533:                }
        !          1534:        }
        !          1535: 
        !          1536:        /*
        !          1537:         * Generate polynomial coefficients a[i] (i = 0...n) from the
        !          1538:         * expansion of root products (x - x[j]) mod q for all j. The
        !          1539:         * method is a present from Charlie Boncelet.
        !          1540:         */
        !          1541:        for (i = 0; i <= n; i++) {
        !          1542:                a[i] = BN_new();
        !          1543: 
        !          1544:                BN_one(a[i]);
        !          1545:        }
        !          1546:        for (j = 1; j <= n; j++) {
        !          1547:                BN_zero(w);
        !          1548:                for (i = 0; i < j; i++) {
        !          1549:                        BN_copy(u, dsa->q);
        !          1550:                        BN_mod_mul(v, a[i], x[j], dsa->q, ctx);
        !          1551:                        BN_sub(u, u, v);
        !          1552:                        BN_add(u, u, w);
        !          1553:                        BN_copy(w, a[i]);
        !          1554:                        BN_mod(a[i], u, dsa->q, ctx);
        !          1555:                }
        !          1556:        }
        !          1557: 
        !          1558:        /*
        !          1559:         * Generate g[i] = g^a[i] mod p for all i and the generator g.
        !          1560:         */
        !          1561:        for (i = 0; i <= n; i++) {
        !          1562:                g[i] = BN_new();
        !          1563: 
        !          1564:                BN_mod_exp(g[i], dsa->g, a[i], dsa->p, ctx);
        !          1565:        }
        !          1566: 
        !          1567:        /*
        !          1568:         * Verify prod(g[i]^(a[i] x[j]^i)) = 1 for all i, j. Note the
        !          1569:         * a[i] x[j]^i exponent is computed mod q, but the g[i] is
        !          1570:         * computed mod p. also note the expression given in the paper
        !          1571:         * is incorrect.
        !          1572:         */
        !          1573:        temp = 1;
        !          1574:        for (j = 1; j <= n; j++) {
        !          1575:                BN_one(u);
        !          1576:                for (i = 0; i <= n; i++) {
        !          1577:                        BN_set_word(v, i);
        !          1578:                        BN_mod_exp(v, x[j], v, dsa->q, ctx);
        !          1579:                        BN_mod_mul(v, v, a[i], dsa->q, ctx);
        !          1580:                        BN_mod_exp(v, dsa->g, v, dsa->p, ctx);
        !          1581:                        BN_mod_mul(u, u, v, dsa->p, ctx);
        !          1582:                }
        !          1583:                if (!BN_is_one(u))
        !          1584:                        temp = 0;
        !          1585:        }
        !          1586:        fprintf(stderr,
        !          1587:            "Confirm prod(g[i]^(x[j]^i)) = 1 for all i, j: %s\n", temp ?
        !          1588:            "yes" : "no");
        !          1589:        if (!temp) {
        !          1590:                return (NULL);
        !          1591:        }
        !          1592: 
        !          1593:        /*
        !          1594:         * Make private encryption key A. Keep it around for awhile,
        !          1595:         * since it is expensive to compute.
        !          1596:         */
        !          1597:        biga = BN_new();
        !          1598: 
        !          1599:        BN_one(biga);
        !          1600:        for (j = 1; j <= n; j++) {
        !          1601:                for (i = 0; i < n; i++) {
        !          1602:                        BN_set_word(v, i);
        !          1603:                        BN_mod_exp(v, x[j], v, dsa->q, ctx);
        !          1604:                        BN_mod_exp(v, g[i], v, dsa->p, ctx);
        !          1605:                        BN_mod_mul(biga, biga, v, dsa->p, ctx);
        !          1606:                }
        !          1607:        }
        !          1608: 
        !          1609:        /*
        !          1610:         * Roll private random group key b mod q (0 < b < q), where
        !          1611:         * gcd(b, q) = 1 to guarantee b^-1 exists, then compute b^-1
        !          1612:         * mod q. If b is changed, the client keys must be recomputed.
        !          1613:         */
        !          1614:        while (1) {
        !          1615:                BN_rand(b, BN_num_bits(dsa->q), 0, 0);
        !          1616:                BN_mod(b, b, dsa->q, ctx);
        !          1617:                BN_gcd(u, b, dsa->q, ctx);
        !          1618:                if (BN_is_one(u))
        !          1619:                        break;
        !          1620:        }
        !          1621:        BN_mod_inverse(b1, b, dsa->q, ctx);
        !          1622: 
        !          1623:        /*
        !          1624:         * Make private client keys (xbar[j], xhat[j]) for all j. Note
        !          1625:         * that the keys for the jth client do not s1[j] or the product
        !          1626:         * s1[j]) (j = 1...n) which is q by construction.
        !          1627:         *
        !          1628:         * Compute the factor w such that w s1[j] = s1[j] for all j. The
        !          1629:         * easy way to do this is to compute (q + s1[j]) / s1[j].
        !          1630:         * Exercise for the student: prove the remainder is always zero.
        !          1631:         */
        !          1632:        for (j = 1; j <= n; j++) {
        !          1633:                xbar[j] = BN_new(); xhat[j] = BN_new();
        !          1634: 
        !          1635:                BN_add(w, dsa->q, s1[j]);
        !          1636:                BN_div(w, u, w, s1[j], ctx);
        !          1637:                BN_zero(xbar[j]);
        !          1638:                BN_set_word(v, n);
        !          1639:                for (i = 1; i <= n; i++) {
        !          1640:                        if (i == j)
        !          1641:                                continue;
        !          1642:                        BN_mod_exp(u, x[i], v, dsa->q, ctx);
        !          1643:                        BN_add(xbar[j], xbar[j], u);
        !          1644:                }
        !          1645:                BN_mod_mul(xbar[j], xbar[j], b1, dsa->q, ctx);
        !          1646:                BN_mod_exp(xhat[j], x[j], v, dsa->q, ctx);
        !          1647:                BN_mod_mul(xhat[j], xhat[j], w, dsa->q, ctx);
        !          1648:        }
        !          1649: 
        !          1650:        /*
        !          1651:         * We revoke client j by dividing q by s1[j]. The quotient
        !          1652:         * becomes the enabling key s. Note we always have to revoke
        !          1653:         * one key; otherwise, the plaintext and cryptotext would be
        !          1654:         * identical. For the present there are no provisions to revoke
        !          1655:         * additional keys, so we sail on with only token revocations.
        !          1656:         */
        !          1657:        s = BN_new();
        !          1658: 
        !          1659:        BN_copy(s, dsa->q);
        !          1660:        BN_div(s, u, s, s1[n], ctx);
        !          1661: 
        !          1662:        /*
        !          1663:         * For each combination of clients to be revoked, make private
        !          1664:         * encryption key E = A^s and partial decryption keys gbar = g^s
        !          1665:         * and ghat = g^(s b), all mod p. The servers use these keys to
        !          1666:         * compute the session encryption key and partial decryption
        !          1667:         * keys. These values must be regenerated if the enabling key is
        !          1668:         * changed.
        !          1669:         */
        !          1670:        bige = BN_new(); gbar = BN_new(); ghat = BN_new();
        !          1671: 
        !          1672:        BN_mod_exp(bige, biga, s, dsa->p, ctx);
        !          1673:        BN_mod_exp(gbar, dsa->g, s, dsa->p, ctx);
        !          1674:        BN_mod_mul(v, s, b, dsa->q, ctx);
        !          1675:        BN_mod_exp(ghat, dsa->g, v, dsa->p, ctx);
        !          1676:        
        !          1677:        /*
        !          1678:         * Notes: We produce the key media in three steps. The first
        !          1679:         * step is to generate the system parameters p, q, g, b, A and
        !          1680:         * the enabling keys s1[j]. Associated with each s1[j] are
        !          1681:         * parameters xbar[j] and xhat[j]. All of these parameters are
        !          1682:         * retained in a data structure protecteted by the trusted-agent
        !          1683:         * password. The p, xbar[j] and xhat[j] paremeters are
        !          1684:         * distributed to the j clients. When the client keys are to be
        !          1685:         * activated, the enabled keys are multipied together to form
        !          1686:         * the master enabling key s. This and the other parameters are
        !          1687:         * used to compute the server encryption key E and the partial
        !          1688:         * decryption keys gbar and ghat.
        !          1689:         *
        !          1690:         * In the identity exchange the client rolls random r and sends
        !          1691:         * it to the server. The server rolls random k, which is used
        !          1692:         * only once, then computes the session key E^k and partial
        !          1693:         * decryption keys gbar^k and ghat^k. The server sends the
        !          1694:         * encrypted r along with gbar^k and ghat^k to the client. The
        !          1695:         * client completes the decryption and verifies it matches r.
        !          1696:         */
        !          1697:        /*
        !          1698:         * Write the MV trusted-agent parameters and keys as a DSA
        !          1699:         * private key encoded in PEM.
        !          1700:         *
        !          1701:         * p    modulus p
        !          1702:         * q    modulus q
        !          1703:         * g    generator g
        !          1704:         * priv_key A mod p
        !          1705:         * pub_key b mod q
        !          1706:         * (remaining values are not used)
        !          1707:         */
        !          1708:        i = 0;
        !          1709:        str = fheader("MVta", "mvta", groupname);
        !          1710:        fprintf(stderr, "Generating MV trusted-authority keys\n");
        !          1711:        BN_copy(dsa->priv_key, biga);
        !          1712:        BN_copy(dsa->pub_key, b);
        !          1713:        pkey = EVP_PKEY_new();
        !          1714:        EVP_PKEY_assign_DSA(pkey, dsa);
        !          1715:        PEM_write_PrivateKey(str, pkey, EVP_des_cbc(), NULL, 0, NULL,
        !          1716:            passwd1);
        !          1717:        evpars[i++] = pkey;
        !          1718:        if (debug)
        !          1719:                DSA_print_fp(stderr, dsa, 0);
        !          1720: 
        !          1721:        /*
        !          1722:         * Append the MV server parameters and keys as a DSA key encoded
        !          1723:         * in PEM.
        !          1724:         *
        !          1725:         * p    modulus p
        !          1726:         * q    modulus q (used only when generating k)
        !          1727:         * g    bige
        !          1728:         * priv_key gbar
        !          1729:         * pub_key ghat
        !          1730:         * (remaining values are not used)
        !          1731:         */
        !          1732:        fprintf(stderr, "Generating MV server keys\n");
        !          1733:        dsa2 = DSA_new();
        !          1734:        dsa2->p = BN_dup(dsa->p);
        !          1735:        dsa2->q = BN_dup(dsa->q); 
        !          1736:        dsa2->g = BN_dup(bige); 
        !          1737:        dsa2->priv_key = BN_dup(gbar);
        !          1738:        dsa2->pub_key = BN_dup(ghat);
        !          1739:        pkey1 = EVP_PKEY_new();
        !          1740:        EVP_PKEY_assign_DSA(pkey1, dsa2);
        !          1741:        PEM_write_PrivateKey(str, pkey1, EVP_des_cbc(), NULL, 0, NULL,
        !          1742:            passwd1);
        !          1743:        evpars[i++] = pkey1;
        !          1744:        if (debug)
        !          1745:                DSA_print_fp(stderr, dsa2, 0);
        !          1746: 
        !          1747:        /*
        !          1748:         * Append the MV client parameters for each client j as DSA keys
        !          1749:         * encoded in PEM.
        !          1750:         *
        !          1751:         * p    modulus p
        !          1752:         * priv_key xbar[j] mod q
        !          1753:         * pub_key xhat[j] mod q
        !          1754:         * (remaining values are not used)
        !          1755:         */
        !          1756:        fprintf(stderr, "Generating %d MV client keys\n", n);
        !          1757:        for (j = 1; j <= n; j++) {
        !          1758:                sdsa = DSA_new();
        !          1759: 
        !          1760:                sdsa->p = BN_dup(dsa->p);
        !          1761:                sdsa->q = BN_dup(BN_value_one()); 
        !          1762:                sdsa->g = BN_dup(BN_value_one()); 
        !          1763:                sdsa->priv_key = BN_dup(xbar[j]);
        !          1764:                sdsa->pub_key = BN_dup(xhat[j]);
        !          1765:                pkey1 = EVP_PKEY_new();
        !          1766:                EVP_PKEY_set1_DSA(pkey1, sdsa);
        !          1767:                PEM_write_PrivateKey(str, pkey1, EVP_des_cbc(), NULL, 0,
        !          1768:                    NULL, passwd1);
        !          1769:                evpars[i++] = pkey1;
        !          1770:                if (debug)
        !          1771:                        DSA_print_fp(stderr, sdsa, 0);
        !          1772: 
        !          1773:                /*
        !          1774:                 * The product gbar^k)^xbar[j] (ghat^k)^xhat[j] and E
        !          1775:                 * are inverses of each other. We check that the product
        !          1776:                 * is one for each client except the ones that have been
        !          1777:                 * revoked. 
        !          1778:                 */
        !          1779:                BN_mod_exp(v, dsa2->priv_key, sdsa->pub_key, dsa->p,
        !          1780:                    ctx);
        !          1781:                BN_mod_exp(u, dsa2->pub_key, sdsa->priv_key, dsa->p,
        !          1782:                    ctx);
        !          1783:                BN_mod_mul(u, u, v, dsa->p, ctx);
        !          1784:                BN_mod_mul(u, u, bige, dsa->p, ctx);
        !          1785:                if (!BN_is_one(u)) {
        !          1786:                        fprintf(stderr, "Revoke key %d\n", j);
        !          1787:                        continue;
        !          1788:                }
        !          1789:        }
        !          1790:        evpars[i++] = NULL;
        !          1791:        fclose(str);
        !          1792: 
        !          1793:        /*
        !          1794:         * Free the countries.
        !          1795:         */
        !          1796:        for (i = 0; i <= n; i++) {
        !          1797:                BN_free(a[i]); BN_free(g[i]);
        !          1798:        }
        !          1799:        for (j = 1; j <= n; j++) {
        !          1800:                BN_free(x[j]); BN_free(xbar[j]); BN_free(xhat[j]);
        !          1801:                BN_free(s1[j]); 
        !          1802:        }
        !          1803:        return (pkey);
        !          1804: }
        !          1805: 
        !          1806: 
        !          1807: /*
        !          1808:  * Generate X509v3 certificate.
        !          1809:  *
        !          1810:  * The certificate consists of the version number, serial number,
        !          1811:  * validity interval, issuer name, subject name and public key. For a
        !          1812:  * self-signed certificate, the issuer name is the same as the subject
        !          1813:  * name and these items are signed using the subject private key. The
        !          1814:  * validity interval extends from the current time to the same time one
        !          1815:  * year hence. For NTP purposes, it is convenient to use the NTP seconds
        !          1816:  * of the current time as the serial number.
        !          1817:  */
        !          1818: int
        !          1819: x509   (
        !          1820:        EVP_PKEY *pkey,         /* generic signature algorithm */
        !          1821:        const EVP_MD *md,       /* generic digest algorithm */
        !          1822:        char    *gqpub,         /* identity extension (hex string) */
        !          1823:        char    *exten,         /* private cert extension */
        !          1824:        char    *name           /* subject/issuer namd */
        !          1825:        )
        !          1826: {
        !          1827:        X509    *cert;          /* X509 certificate */
        !          1828:        X509_NAME *subj;        /* distinguished (common) name */
        !          1829:        X509_EXTENSION *ex;     /* X509v3 extension */
        !          1830:        FILE    *str;           /* file handle */
        !          1831:        ASN1_INTEGER *serial;   /* serial number */
        !          1832:        const char *id;         /* digest/signature scheme name */
        !          1833:        char    pathbuf[MAXFILENAME + 1];
        !          1834: 
        !          1835:        /*
        !          1836:         * Generate X509 self-signed certificate.
        !          1837:         *
        !          1838:         * Set the certificate serial to the NTP seconds for grins. Set
        !          1839:         * the version to 3. Set the initial validity to the current
        !          1840:         * time and the finalvalidity one year hence.
        !          1841:         */
        !          1842:        id = OBJ_nid2sn(md->pkey_type);
        !          1843:        fprintf(stderr, "Generating new certificate %s %s\n", name, id);
        !          1844:        cert = X509_new();
        !          1845:        X509_set_version(cert, 2L);
        !          1846:        serial = ASN1_INTEGER_new();
        !          1847:        ASN1_INTEGER_set(serial, (long)epoch + JAN_1970);
        !          1848:        X509_set_serialNumber(cert, serial);
        !          1849:        ASN1_INTEGER_free(serial);
        !          1850:        X509_time_adj(X509_get_notBefore(cert), 0L, &epoch);
        !          1851:        X509_time_adj(X509_get_notAfter(cert), YEAR, &epoch);
        !          1852:        subj = X509_get_subject_name(cert);
        !          1853:        X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
        !          1854:            (unsigned char *) name, strlen(name), -1, 0);
        !          1855:        subj = X509_get_issuer_name(cert);
        !          1856:        X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC,
        !          1857:            (unsigned char *) name, strlen(name), -1, 0);
        !          1858:        if (!X509_set_pubkey(cert, pkey)) {
        !          1859:                fprintf(stderr, "Assign key fails\n%s\n",
        !          1860:                    ERR_error_string(ERR_get_error(), NULL));
        !          1861:                X509_free(cert);
        !          1862:                return (0);
        !          1863:        }
        !          1864: 
        !          1865:        /*
        !          1866:         * Add X509v3 extensions if present. These represent the minimum
        !          1867:         * set defined in RFC3280 less the certificate_policy extension,
        !          1868:         * which is seriously obfuscated in OpenSSL.
        !          1869:         */
        !          1870:        /*
        !          1871:         * The basic_constraints extension CA:TRUE allows servers to
        !          1872:         * sign client certficitates.
        !          1873:         */
        !          1874:        fprintf(stderr, "%s: %s\n", LN_basic_constraints,
        !          1875:            BASIC_CONSTRAINTS);
        !          1876:        ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints,
        !          1877:            BASIC_CONSTRAINTS);
        !          1878:        if (!X509_add_ext(cert, ex, -1)) {
        !          1879:                fprintf(stderr, "Add extension field fails\n%s\n",
        !          1880:                    ERR_error_string(ERR_get_error(), NULL));
        !          1881:                return (0);
        !          1882:        }
        !          1883:        X509_EXTENSION_free(ex);
        !          1884: 
        !          1885:        /*
        !          1886:         * The key_usage extension designates the purposes the key can
        !          1887:         * be used for.
        !          1888:         */
        !          1889:        fprintf(stderr, "%s: %s\n", LN_key_usage, KEY_USAGE);
        !          1890:        ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, KEY_USAGE);
        !          1891:        if (!X509_add_ext(cert, ex, -1)) {
        !          1892:                fprintf(stderr, "Add extension field fails\n%s\n",
        !          1893:                    ERR_error_string(ERR_get_error(), NULL));
        !          1894:                return (0);
        !          1895:        }
        !          1896:        X509_EXTENSION_free(ex);
        !          1897:        /*
        !          1898:         * The subject_key_identifier is used for the GQ public key.
        !          1899:         * This should not be controversial.
        !          1900:         */
        !          1901:        if (gqpub != NULL) {
        !          1902:                fprintf(stderr, "%s\n", LN_subject_key_identifier);
        !          1903:                ex = X509V3_EXT_conf_nid(NULL, NULL,
        !          1904:                    NID_subject_key_identifier, gqpub);
        !          1905:                if (!X509_add_ext(cert, ex, -1)) {
        !          1906:                        fprintf(stderr,
        !          1907:                            "Add extension field fails\n%s\n",
        !          1908:                            ERR_error_string(ERR_get_error(), NULL));
        !          1909:                        return (0);
        !          1910:                }
        !          1911:                X509_EXTENSION_free(ex);
        !          1912:        }
        !          1913: 
        !          1914:        /*
        !          1915:         * The extended key usage extension is used for special purpose
        !          1916:         * here. The semantics probably do not conform to the designer's
        !          1917:         * intent and will likely change in future.
        !          1918:         * 
        !          1919:         * "trustRoot" designates a root authority
        !          1920:         * "private" designates a private certificate
        !          1921:         */
        !          1922:        if (exten != NULL) {
        !          1923:                fprintf(stderr, "%s: %s\n", LN_ext_key_usage, exten);
        !          1924:                ex = X509V3_EXT_conf_nid(NULL, NULL,
        !          1925:                    NID_ext_key_usage, exten);
        !          1926:                if (!X509_add_ext(cert, ex, -1)) {
        !          1927:                        fprintf(stderr,
        !          1928:                            "Add extension field fails\n%s\n",
        !          1929:                            ERR_error_string(ERR_get_error(), NULL));
        !          1930:                        return (0);
        !          1931:                }
        !          1932:                X509_EXTENSION_free(ex);
        !          1933:        }
        !          1934: 
        !          1935:        /*
        !          1936:         * Sign and verify.
        !          1937:         */
        !          1938:        X509_sign(cert, pkey, md);
        !          1939:        if (X509_verify(cert, pkey) <= 0) {
        !          1940:                fprintf(stderr, "Verify %s certificate fails\n%s\n", id,
        !          1941:                    ERR_error_string(ERR_get_error(), NULL));
        !          1942:                X509_free(cert);
        !          1943:                return (0);
        !          1944:        }
        !          1945: 
        !          1946:        /*
        !          1947:         * Write the certificate encoded in PEM.
        !          1948:         */
        !          1949:        sprintf(pathbuf, "%scert", id);
        !          1950:        str = fheader(pathbuf, "cert", hostname);
        !          1951:        PEM_write_X509(str, cert);
        !          1952:        fclose(str);
        !          1953:        if (debug)
        !          1954:                X509_print_fp(stderr, cert);
        !          1955:        X509_free(cert);
        !          1956:        return (1);
        !          1957: }
        !          1958: 
        !          1959: #if 0  /* asn2ntp is used only with commercial certificates */
        !          1960: /*
        !          1961:  * asn2ntp - convert ASN1_TIME time structure to NTP time
        !          1962:  */
        !          1963: u_long
        !          1964: asn2ntp        (
        !          1965:        ASN1_TIME *asn1time     /* pointer to ASN1_TIME structure */
        !          1966:        )
        !          1967: {
        !          1968:        char    *v;             /* pointer to ASN1_TIME string */
        !          1969:        struct  tm tm;          /* time decode structure time */
        !          1970: 
        !          1971:        /*
        !          1972:         * Extract time string YYMMDDHHMMSSZ from ASN.1 time structure.
        !          1973:         * Note that the YY, MM, DD fields start with one, the HH, MM,
        !          1974:         * SS fiels start with zero and the Z character should be 'Z'
        !          1975:         * for UTC. Also note that years less than 50 map to years
        !          1976:         * greater than 100. Dontcha love ASN.1?
        !          1977:         */
        !          1978:        if (asn1time->length > 13)
        !          1979:                return (-1);
        !          1980:        v = (char *)asn1time->data;
        !          1981:        tm.tm_year = (v[0] - '0') * 10 + v[1] - '0';
        !          1982:        if (tm.tm_year < 50)
        !          1983:                tm.tm_year += 100;
        !          1984:        tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1;
        !          1985:        tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0';
        !          1986:        tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0';
        !          1987:        tm.tm_min = (v[8] - '0') * 10 + v[9] - '0';
        !          1988:        tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0';
        !          1989:        tm.tm_wday = 0;
        !          1990:        tm.tm_yday = 0;
        !          1991:        tm.tm_isdst = 0;
        !          1992:        return (mktime(&tm) + JAN_1970);
        !          1993: }
        !          1994: #endif
        !          1995: 
        !          1996: /*
        !          1997:  * Callback routine
        !          1998:  */
        !          1999: void
        !          2000: cb     (
        !          2001:        int     n1,             /* arg 1 */
        !          2002:        int     n2,             /* arg 2 */
        !          2003:        void    *chr            /* arg 3 */
        !          2004:        )
        !          2005: {
        !          2006:        switch (n1) {
        !          2007:        case 0:
        !          2008:                d0++;
        !          2009:                fprintf(stderr, "%s %d %d %lu\r", (char *)chr, n1, n2,
        !          2010:                    d0);
        !          2011:                break;
        !          2012:        case 1:
        !          2013:                d1++;
        !          2014:                fprintf(stderr, "%s\t\t%d %d %lu\r", (char *)chr, n1,
        !          2015:                    n2, d1);
        !          2016:                break;
        !          2017:        case 2:
        !          2018:                d2++;
        !          2019:                fprintf(stderr, "%s\t\t\t\t%d %d %lu\r", (char *)chr,
        !          2020:                    n1, n2, d2);
        !          2021:                break;
        !          2022:        case 3:
        !          2023:                d3++;
        !          2024:                fprintf(stderr, "%s\t\t\t\t\t\t%d %d %lu\r",
        !          2025:                    (char *)chr, n1, n2, d3);
        !          2026:                break;
        !          2027:        }
        !          2028: }
        !          2029: 
        !          2030: 
        !          2031: /*
        !          2032:  * Generate key
        !          2033:  */
        !          2034: EVP_PKEY *                     /* public/private key pair */
        !          2035: genkey(
        !          2036:        char    *type,          /* key type (RSA or DSA) */
        !          2037:        char    *id             /* file name id */
        !          2038:        )
        !          2039: {
        !          2040:        if (type == NULL)
        !          2041:                return (NULL);
        !          2042:        if (strcmp(type, "RSA") == 0)
        !          2043:                return (gen_rsa(id));
        !          2044: 
        !          2045:        else if (strcmp(type, "DSA") == 0)
        !          2046:                return (gen_dsa(id));
        !          2047: 
        !          2048:        fprintf(stderr, "Invalid %s key type %s\n", id, type);
        !          2049:        return (NULL);
        !          2050: }
        !          2051: #endif /* OPENSSL */
        !          2052: 
        !          2053: 
        !          2054: /*
        !          2055:  * Generate file header and link
        !          2056:  */
        !          2057: FILE *
        !          2058: fheader        (
        !          2059:        const char *file,       /* file name id */
        !          2060:        const char *ulink,      /* linkname */
        !          2061:        const char *owner       /* owner name */
        !          2062:        )
        !          2063: {
        !          2064:        FILE    *str;           /* file handle */
        !          2065:        char    linkname[MAXFILENAME]; /* link name */
        !          2066:        int     temp;
        !          2067: 
        !          2068:        sprintf(filename, "ntpkey_%s_%s.%lu", file, owner, epoch +
        !          2069:            JAN_1970);
        !          2070:        if ((str = fopen(filename, "w")) == NULL) {
        !          2071:                perror("Write");
        !          2072:                exit (-1);
        !          2073:        }
        !          2074:        sprintf(linkname, "ntpkey_%s_%s", ulink, owner);
        !          2075:        remove(linkname);
        !          2076:        temp = symlink(filename, linkname);
        !          2077:        if (temp < 0)
        !          2078:                perror(file);
        !          2079:        fprintf(stderr, "Generating new %s file and link\n", ulink);
        !          2080:        fprintf(stderr, "%s->%s\n", linkname, filename);
        !          2081:        fprintf(str, "# %s\n# %s\n", filename, ctime(&epoch));
        !          2082:        return (str);
        !          2083: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>