📄 ntp-keygen.c
字号:
BN_one(u); for (i = 0; i <= n; i++) { BN_set_word(v, i); BN_mod_exp(v, x[j], v, dsa->q, ctx); BN_mod_mul(v, v, a[i], dsa->q, ctx); BN_mod_exp(v, dsa->g, v, dsa->p, ctx); BN_mod_mul(u, u, v, dsa->p, ctx); } if (!BN_is_one(u)) temp = 0; } fprintf(stderr, "Confirm prod(g[i]^(x[j]^i)) = 1 for all i, j: %s\n", temp ? "yes" : "no"); if (!temp) { rval = -1; return (NULL); } /* * Make private encryption key A. Keep it around for awhile, * since it is expensive to compute. */ biga = BN_new(); BN_one(biga); for (j = 1; j <= n; j++) { for (i = 0; i < n; i++) { BN_set_word(v, i); BN_mod_exp(v, x[j], v, dsa->q, ctx); BN_mod_exp(v, g[i], v, dsa->p, ctx); BN_mod_mul(biga, biga, v, dsa->p, ctx); } } /* * Roll private random group key b mod q (0 < b < q), where * gcd(b, q) = 1 to guarantee b^1 exists, then compute b^-1 * mod q. If b is changed, the client keys must be recomputed. */ while (1) { BN_rand(b, BN_num_bits(dsa->q), 0, 0); BN_mod(b, b, dsa->q, ctx); BN_gcd(u, b, dsa->q, ctx); if (BN_is_one(u)) break; } BN_mod_inverse(b1, b, dsa->q, ctx); /* * Make private client keys (xbar[j], xhat[j]) for all j. Note * that the keys for the jth client involve s[j], but not s'[j] * or the product s = prod(s'[j]) mod q, which is the enabling * key. */ xbar = malloc((n + 1) * sizeof(BIGNUM)); xhat = malloc((n + 1) * sizeof(BIGNUM)); for (j = 1; j <= n; j++) { xbar[j] = BN_new(); xhat[j] = BN_new(); BN_zero(xbar[j]); BN_set_word(v, n); for (i = 1; i <= n; i++) { if (i == j) continue; BN_mod_exp(u, x[i], v, dsa->q, ctx); BN_add(xbar[j], xbar[j], u); } BN_mod_mul(xbar[j], xbar[j], b1, dsa->q, ctx); BN_mod_exp(xhat[j], x[j], v, dsa->q, ctx); BN_mod_mul(xhat[j], xhat[j], s[j], dsa->q, ctx); } /* * The enabling key is initially q by construction. We can * revoke client j by dividing q by s'[j]. The quotient becomes * the enabling key s. Note we always have to revoke one key; * otherwise, the plaintext and cryptotext would be identical. */ ss = BN_new(); BN_copy(ss, dsa->q); BN_div(ss, u, dsa->q, s1[n], ctx); /* * Make private server encryption key E = A^s and public server * keys gbar = g^s mod p and ghat = g^(s b) mod p. The (gbar, * ghat) is the public key provided to the server, which uses it * to compute the session encryption key and public key included * in its messages. These values must be regenerated if the * enabling key is changed. */ bige = BN_new(); gbar = BN_new(); ghat = BN_new(); BN_mod_exp(bige, biga, ss, dsa->p, ctx); BN_mod_exp(gbar, dsa->g, ss, dsa->p, ctx); BN_mod_mul(v, ss, b, dsa->q, ctx); BN_mod_exp(ghat, dsa->g, v, dsa->p, ctx); /* * We produce the key media in three steps. The first step is to * generate the private values that do not depend on the * enabling key. These include the server values p, q, g, b, A * and the client values s'[j], xbar[j] and xhat[j] for each j. * The p, xbar[j] and xhat[j] values are encoded in private * files which are distributed to respective clients. The p, q, * g, A and s'[j] values (will be) written to a secret file to * be read back later. * * The secret file (will be) read back at some later time to * enable/disable individual keys and generate/regenerate the * enabling key s. The p, q, E, gbar and ghat values are written * to a secret file to be read back later by the server. * * The server reads the secret file and rolls the session key * k, which is used only once, then computes E^k, gbar^k and * ghat^k. The E^k is the session encryption key. The encrypted * data, gbar^k and ghat^k are transmtted to clients in an * extension field. The client receives the message and computes * x = (gbar^k)^xbar[j] (ghat^k)^xhat[j], finds the session * encryption key E^k as the inverse x^-1 and decrypts the data. */ BN_copy(dsa->g, bige); dsa->priv_key = BN_dup(gbar); dsa->pub_key = BN_dup(ghat); /* * Write the MV server parameters and keys as a DSA private key * encoded in PEM. * * p modulus p * q modulus q (used only to generate k) * g E mod p * priv_key gbar mod p * pub_key ghat mod p */ str = fheader("MVpar", trustname); pkey = EVP_PKEY_new(); EVP_PKEY_assign_DSA(pkey, dsa); PEM_write_PrivateKey(str, pkey, passwd2 ? EVP_des_cbc() : NULL, NULL, 0, NULL, passwd2); fclose(str); if (debug) DSA_print_fp(stdout, dsa, 0); fslink(id, trustname); /* * Write the parameters and private key (xbar[j], xhat[j]) for * all j as a DSA private key encoded in PEM. It is used only by * the designated recipient(s) who pay a suitably outrageous fee * for its use. */ sdsa = DSA_new(); sdsa->p = BN_dup(dsa->p); sdsa->q = BN_dup(BN_value_one()); sdsa->g = BN_dup(BN_value_one()); sdsa->priv_key = BN_new(); sdsa->pub_key = BN_new(); for (j = 1; j <= n; j++) { BN_copy(sdsa->priv_key, xbar[j]); BN_copy(sdsa->pub_key, xhat[j]); BN_mod_exp(v, dsa->priv_key, sdsa->pub_key, dsa->p, ctx); BN_mod_exp(u, dsa->pub_key, sdsa->priv_key, dsa->p, ctx); BN_mod_mul(u, u, v, dsa->p, ctx); BN_mod_mul(u, u, dsa->g, dsa->p, ctx); BN_free(xbar[j]); BN_free(xhat[j]); BN_free(x[j]); BN_free(s[j]); BN_free(s1[j]); if (!BN_is_one(u)) { fprintf(stderr, "Revoke key %d\n", j); continue; } /* * Write the client parameters as a DSA private key * encoded in PEM. We don't make links for these. * * p modulus p * priv_key xbar[j] mod q * pub_key xhat[j] mod q * (remaining values are not used) */ sprintf(ident, "MVkey%d", j); str = fheader(ident, trustname); pkey1 = EVP_PKEY_new(); EVP_PKEY_set1_DSA(pkey1, sdsa); PEM_write_PrivateKey(str, pkey1, passwd2 ? EVP_des_cbc() : NULL, NULL, 0, NULL, passwd2); fclose(str); fprintf(stderr, "ntpkey_%s_%s.%lu\n", ident, trustname, epoch + JAN_1970); if (debug) DSA_print_fp(stdout, sdsa, 0); EVP_PKEY_free(pkey1); } /* * Free the countries. */ for (i = 0; i <= n; i++) { BN_free(a[i]); BN_free(g[i]); } BN_free(u); BN_free(v); BN_free(w); BN_CTX_free(ctx); BN_free(b); BN_free(b1); BN_free(biga); BN_free(bige); BN_free(ss); BN_free(gbar); BN_free(ghat); DSA_free(sdsa); /* * Free the world. */ free(x); free(a); free(g); free(s); free(s1); free(xbar); free(xhat); return (pkey);}/* * Generate X509v3 scertificate. * * The certificate consists of the version number, serial number, * validity interval, issuer name, subject name and public key. For a * self-signed certificate, the issuer name is the same as the subject * name and these items are signed using the subject private key. The * validity interval extends from the current time to the same time one * year hence. For NTP purposes, it is convenient to use the NTP seconds * of the current time as the serial number. */intx509 ( EVP_PKEY *pkey, /* generic signature algorithm */ const EVP_MD *md, /* generic digest algorithm */ char *gqpub, /* identity extension (hex string) */ char *exten /* private cert extension */ ){ X509 *cert; /* X509 certificate */ X509_NAME *subj; /* distinguished (common) name */ X509_EXTENSION *ex; /* X509v3 extension */ FILE *str; /* file handle */ ASN1_INTEGER *serial; /* serial number */ const char *id; /* digest/signature scheme name */ char pathbuf[MAXFILENAME + 1]; /* * Generate X509 self-signed certificate. * * Set the certificate serial to the NTP seconds for grins. Set * the version to 3. Set the subject name and issuer name to the * subject name in the request. Set the initial validity to the * current time and the final validity one year hence. */ id = OBJ_nid2sn(md->pkey_type); fprintf(stderr, "Generating certificate %s\n", id); cert = X509_new(); X509_set_version(cert, 2L); serial = ASN1_INTEGER_new(); ASN1_INTEGER_set(serial, epoch + JAN_1970); X509_set_serialNumber(cert, serial); ASN1_INTEGER_free(serial); X509_time_adj(X509_get_notBefore(cert), 0L, &epoch); X509_time_adj(X509_get_notAfter(cert), YEAR, &epoch); subj = X509_get_subject_name(cert); X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, (unsigned char *) hostname, strlen(hostname), -1, 0); subj = X509_get_issuer_name(cert); X509_NAME_add_entry_by_txt(subj, "commonName", MBSTRING_ASC, (unsigned char *) trustname, strlen(trustname), -1, 0); if (!X509_set_pubkey(cert, pkey)) { fprintf(stderr, "Assign key fails\n%s\n", ERR_error_string(ERR_get_error(), NULL)); X509_free(cert); rval = -1; return (0); } /* * Add X509v3 extensions if present. These represent the minimum * set defined in RFC3280 less the certificate_policy extension, * which is seriously obfuscated in OpenSSL. */ /* * The basic_constraints extension CA:TRUE allows servers to * sign client certficitates. */ fprintf(stderr, "%s: %s\n", LN_basic_constraints, BASIC_CONSTRAINTS); ex = X509V3_EXT_conf_nid(NULL, NULL, NID_basic_constraints, BASIC_CONSTRAINTS); if (!X509_add_ext(cert, ex, -1)) { fprintf(stderr, "Add extension field fails\n%s\n", ERR_error_string(ERR_get_error(), NULL)); rval = -1; return (0); } X509_EXTENSION_free(ex); /* * The key_usage extension designates the purposes the key can * be used for. */ fprintf(stderr, "%s: %s\n", LN_key_usage, KEY_USAGE); ex = X509V3_EXT_conf_nid(NULL, NULL, NID_key_usage, KEY_USAGE); if (!X509_add_ext(cert, ex, -1)) { fprintf(stderr, "Add extension field fails\n%s\n", ERR_error_string(ERR_get_error(), NULL)); rval = -1; return (0); } X509_EXTENSION_free(ex); /* * The subject_key_identifier is used for the GQ public key. * This should not be controversial. */ if (gqpub != NULL) { fprintf(stderr, "%s\n", LN_subject_key_identifier); ex = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_key_identifier, gqpub); if (!X509_add_ext(cert, ex, -1)) { fprintf(stderr, "Add extension field fails\n%s\n", ERR_error_string(ERR_get_error(), NULL)); rval = -1; return (0); } X509_EXTENSION_free(ex); } /* * The extended key usage extension is used for special purpose * here. The semantics probably do not conform to the designer's * intent and will likely change in future. * * "trustRoot" designates a root authority * "private" designates a private certificate */ if (exten != NULL) { fprintf(stderr, "%s: %s\n", LN_ext_key_usage, exten); ex = X509V3_EXT_conf_nid(NULL, NULL, NID_ext_key_usage, exten); if (!X509_add_ext(cert, ex, -1)) { fprintf(stderr, "Add extension field fails\n%s\n", ERR_error_string(ERR_get_error(), NULL)); rval = -1; return (0); } X509_EXTENSION_free(ex); } /* * Sign and verify. */ X509_sign(cert, pkey, md); if (!X509_verify(cert, pkey)) { fprintf(stderr, "Verify %s certificate fails\n%s\n", id, ERR_error_string(ERR_get_error(), NULL)); X509_free(cert); rval = -1; return (0); } /* * Write the certificate encoded in PEM. */ sprintf(pathbuf, "%scert", id); str = fheader(pathbuf, hostname); PEM_write_X509(str, cert); fclose(str); if (debug) X509_print_fp(stdout, cert); X509_free(cert); fslink("cert", hostname); return (1);}#if 0 /* asn2ntp is not used *//* * asn2ntp - convert ASN1_TIME time structure to NTP time */u_longasn2ntp ( ASN1_TIME *asn1time /* pointer to ASN1_TIME structure */ ){ char *v; /* pointer to ASN1_TIME string */ struct tm tm; /* time decode structure time */ /* * Extract time string YYMMDDHHMMSSZ from ASN.1 time structure. * Note that the YY, MM, DD fields start with one, the HH, MM, * SS fiels start with zero and the Z character should be 'Z' * for UTC. Also note that years less than 50 map to years * greater than 100. Dontcha love ASN.1? */ if (asn1time->length > 13) return (-1); v = (char *)asn1time->data; tm.tm_year = (v[0] - '0') * 10 + v[1] - '0'; if (tm.tm_year < 50) tm.tm_year += 100; tm.tm_mon = (v[2] - '0') * 10 + v[3] - '0' - 1; tm.tm_mday = (v[4] - '0') * 10 + v[5] - '0'; tm.tm_hour = (v[6] - '0') * 10 + v[7] - '0'; tm.tm_min = (v[8] - '0') * 10 + v[9] - '0'; tm.tm_sec = (v[10] - '0') * 10 + v[11] - '0'; tm.tm_wday = 0; tm.tm_yday = 0; tm.tm_isdst = 0; return (mktime(&tm) + JAN_1970);}#endif/* * Callback routine */voidcb ( int n1, /* arg 1 */ int n2, /* arg 2 */ void *chr /* arg 3 */ ){ switch (n1) { case 0: d0++; fprintf(stderr, "%s %d %d %lu\r", (char *)chr, n1, n2, d0); break; case 1: d1++; fprintf(stderr, "%s\t\t%d %d %lu\r", (char *)chr, n1, n2, d1); break; case 2: d2++; fprintf(stderr, "%s\t\t\t\t%d %d %lu\r", (char *)chr, n1, n2, d2); break; case 3: d3++; fprintf(stderr, "%s\t\t\t\t\t\t%d %d %lu\r", (char *)chr, n1, n2, d3); break; }}/* * Generate key */EVP_PKEY * /* public/private key pair */genkey( char *type, /* key type (RSA or DSA) */ char *id /* file name id */ ){ if (type == NULL) return (NULL); if (strcmp(type, "RSA") == 0) return (gen_rsa(id)); else if (strcmp(type, "DSA") == 0) return (gen_dsa(id)); fprintf(stderr, "Invalid %s key type %s\n", id, type); rval = -1; return (NULL);}#endif /* OPENSSL *//* * Generate file header */FILE *fheader ( const char *id, /* file name id */ const char *name /* owner name */ ){ FILE *str; /* file handle */ sprintf(filename, "ntpkey_%s_%s.%lu", id, name, epoch + JAN_1970); if ((str = fopen(filename, "w")) == NULL) { perror("Write"); exit (-1); } fprintf(str, "# %s\n# %s", filename, ctime(&epoch)); return (str);}/* * Generate symbolic links */voidfslink( const char *id, /* file name id */ const char *name /* owner name */ ){ char linkname[MAXFILENAME]; /* link name */ int temp; sprintf(linkname, "ntpkey_%s_%s", id, name); remove(linkname); temp = symlink(filename, linkname); if (temp < 0) perror(id); fprintf(stderr, "Generating new %s file and link\n", id); fprintf(stderr, "%s->%s\n", linkname, filename);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -