📄 crypto.c
字号:
state = PARSE_FINISHED; } } /* reading key */ if (state == PARSE_DATA) { if (isxdigit(c)) { ASSERT (hb_index >= 0 && hb_index < 2); hex_byte[hb_index++] = c; if (hb_index == 2) { unsigned int u; ASSERT(sscanf((const char *)hex_byte, "%x", &u) == 1); *out++ = u; hb_index = 0; if (++count == keylen) state = PARSE_DATA_COMPLETE; } } else if (isspace(c)) ; else { msg (M_FATAL, (isprint (c) ? printable_char_fmt : unprintable_char_fmt), c, line_num, filename, count, onekeylen, keylen); } } ++line_index; } ++cp; --size; } } close (fd); /* * Normally we will read either 1 or 2 keys from file. */ key2->n = count / onekeylen; ASSERT (key2->n >= 0 && key2->n <= (int) SIZE (key2->keys)); if (must_succeed) { if (!key2->n) msg (M_FATAL, "Insufficient key material or header text not found found in file '%s' (%d/%d/%d bytes found/min/max)", filename, count, onekeylen, keylen); if (state != PARSE_FINISHED) msg (M_FATAL, "Footer text not found in file '%s' (%d/%d/%d bytes found/min/max)", filename, count, onekeylen, keylen); } /* zero file read buffer */ buf_clear (&in); if (key2->n) warn_if_group_others_accessible (filename);#if 0 /* DEBUGGING */ { int i; printf ("KEY READ, n=%d\n", key2->n); for (i = 0; i < (int) SIZE (key2->keys); ++i) { /* format key as ascii */ const char *fmt = format_hex_ex ((const uint8_t*)&key2->keys[i], sizeof (key2->keys[i]), 0, 16, "\n", &gc); printf ("[%d]\n%s\n\n", i, fmt); } }#endif /* pop our garbage collection level */ gc_free (&gc);}intread_passphrase_hash (const char *passphrase_file, const EVP_MD *digest, uint8_t *output, int len){ unsigned int outlen = 0; EVP_MD_CTX md; ASSERT (len >= EVP_MD_size (digest)); memset (output, 0, len); EVP_DigestInit (&md, digest); /* read passphrase file */ { const int min_passphrase_size = 8; uint8_t buf[64]; int total_size = 0; int fd = open (passphrase_file, O_RDONLY); if (fd == -1) msg (M_ERR, "Cannot open passphrase file: '%s'", passphrase_file); for (;;) { int size = read (fd, buf, sizeof (buf)); if (size == 0) break; if (size == -1) msg (M_ERR, "Read error on passphrase file: '%s'", passphrase_file); EVP_DigestUpdate (&md, buf, size); total_size += size; } close (fd); warn_if_group_others_accessible (passphrase_file); if (total_size < min_passphrase_size) msg (M_FATAL, "Passphrase file '%s' is too small (must have at least %d characters)", passphrase_file, min_passphrase_size); } EVP_DigestFinal (&md, output, &outlen); EVP_MD_CTX_cleanup (&md); return outlen;}/* * Write key to file, return number of random bits * written. */intwrite_key_file (const int nkeys, const char *filename){ struct gc_arena gc = gc_new (); int fd, i; int nbits = 0; /* must be large enough to hold full key file */ struct buffer out = alloc_buf_gc (2048, &gc); struct buffer nbits_head_text = alloc_buf_gc (128, &gc); /* how to format the ascii file representation of key */ const int bytes_per_line = 16; /* open key file */ fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); if (fd == -1) msg (M_ERR, "Cannot open shared secret file '%s' for write", filename); buf_printf (&out, "%s\n", static_key_head); for (i = 0; i < nkeys; ++i) { struct key key; char* fmt; /* generate random bits */ generate_key_random (&key, NULL); /* format key as ascii */ fmt = format_hex_ex ((const uint8_t*)&key, sizeof (key), 0, bytes_per_line, "\n", &gc); /* increment random bits counter */ nbits += sizeof (key) * 8; /* write to holding buffer */ buf_printf (&out, "%s\n", fmt); /* zero memory which held key component (will be freed by GC) */ memset (fmt, 0, strlen(fmt)); CLEAR (key); } buf_printf (&out, "%s\n", static_key_foot); /* write number of bits */ buf_printf (&nbits_head_text, "#\n# %d bit " PACKAGE_NAME " static key\n#\n", nbits); buf_write_string_file (&nbits_head_text, filename, fd); /* write key file, now formatted in out, to file */ buf_write_string_file (&out, filename, fd); if (close (fd)) msg (M_ERR, "Close error on shared secret file %s", filename); /* zero memory which held file content (memory will be freed by GC) */ buf_clear (&out); /* pop our garbage collection level */ gc_free (&gc); return nbits;}voidmust_have_n_keys (const char *filename, const char *option, const struct key2 *key2, int n){ if (key2->n < n) msg (M_FATAL, "Key file '%s' used in --%s contains insufficient key material [keys found=%d required=%d] -- try generating a new key file with '" PACKAGE " --genkey --secret [file]', or use the existing key file in bidirectional mode by specifying --%s without a key direction parameter", filename, option, key2->n, n, option);}intascii2keydirection (const char *str){ if (!str) return KEY_DIRECTION_BIDIRECTIONAL; else if (!strcmp (str, "0")) return KEY_DIRECTION_NORMAL; else if (!strcmp (str, "1")) return KEY_DIRECTION_INVERSE; else msg (M_USAGE, "Unknown key direction '%s' -- must be '0' or '1'", str); return KEY_DIRECTION_BIDIRECTIONAL; /* NOTREACHED */}const char *keydirection2ascii (int kd, bool remote){ if (kd == KEY_DIRECTION_BIDIRECTIONAL) return NULL; else if (kd == KEY_DIRECTION_NORMAL) return remote ? "1" : "0"; else if (kd == KEY_DIRECTION_INVERSE) return remote ? "0" : "1"; else { ASSERT (0); } return NULL; /* NOTREACHED */}voidkey_direction_state_init (struct key_direction_state *kds, int key_direction){ CLEAR (*kds); switch (key_direction) { case KEY_DIRECTION_NORMAL: kds->out_key = 0; kds->in_key = 1; kds->need_keys = 2; break; case KEY_DIRECTION_INVERSE: kds->out_key = 1; kds->in_key = 0; kds->need_keys = 2; break; case KEY_DIRECTION_BIDIRECTIONAL: kds->out_key = 0; kds->in_key = 0; kds->need_keys = 1; break; default: ASSERT (0); }}voidverify_fix_key2 (struct key2 *key2, const struct key_type *kt, const char *shared_secret_file){ int i; for (i = 0; i < key2->n; ++i) { /* Fix parity for DES keys and make sure not a weak key */ fixup_key (&key2->keys[i], kt); /* This should be a very improbable failure */ if (!check_key (&key2->keys[i], kt)) msg (M_FATAL, "Key #%d in '%s' is bad. Try making a new key with --genkey.", i+1, shared_secret_file); }}/* given a key and key_type, write key to buffer */voidwrite_key (const struct key *key, const struct key_type *kt, struct buffer *buf){ ASSERT (kt->cipher_length <= MAX_CIPHER_KEY_LENGTH && kt->hmac_length <= MAX_HMAC_KEY_LENGTH); ASSERT (buf_write (buf, &kt->cipher_length, 1)); ASSERT (buf_write (buf, &kt->hmac_length, 1)); ASSERT (buf_write (buf, key->cipher, kt->cipher_length)); ASSERT (buf_write (buf, key->hmac, kt->hmac_length));}/* * Given a key_type and buffer, read key from buffer. * Return: 1 on success * -1 read failure * 0 on key length mismatch */intread_key (struct key *key, const struct key_type *kt, struct buffer *buf){ uint8_t cipher_length; uint8_t hmac_length; CLEAR (*key); if (!buf_read (buf, &cipher_length, 1)) goto read_err; if (!buf_read (buf, &hmac_length, 1)) goto read_err; if (!buf_read (buf, key->cipher, cipher_length)) goto read_err; if (!buf_read (buf, key->hmac, hmac_length)) goto read_err; if (cipher_length != kt->cipher_length || hmac_length != kt->hmac_length) goto key_len_err; return 1;read_err: msg (D_TLS_ERRORS, "TLS Error: error reading key from remote"); return -1;key_len_err: msg (D_TLS_ERRORS, "TLS Error: key length mismatch, local cipher/hmac %d/%d, remote cipher/hmac %d/%d", kt->cipher_length, kt->hmac_length, cipher_length, hmac_length); return 0;}voidshow_available_ciphers (){ int nid; printf ("The following ciphers and cipher modes are available\n" "for use with " PACKAGE_NAME ". Each cipher shown below may be\n" "used as a parameter to the --cipher option. The default\n" "key size is shown as well as whether or not it can be\n" "changed with the --keysize directive. Using a CBC mode\n" "is recommended.\n\n"); for (nid = 0; nid < 10000; ++nid) /* is there a better way to get the size of the nid list? */ { const EVP_CIPHER *cipher = EVP_get_cipherbynid (nid); if (cipher && cipher_ok (OBJ_nid2sn (nid))) { const unsigned int mode = EVP_CIPHER_mode (cipher); if (mode == EVP_CIPH_CBC_MODE#ifdef ALLOW_NON_CBC_CIPHERS || mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE#endif ) printf ("%s %d bit default key (%s)\n", OBJ_nid2sn (nid), EVP_CIPHER_key_length (cipher) * 8, ((EVP_CIPHER_flags (cipher) & EVP_CIPH_VARIABLE_LENGTH) ? "variable" : "fixed")); } } printf ("\n");}voidshow_available_digests (){ int nid; printf ("The following message digests are available for use with\n" PACKAGE_NAME ". A message digest is used in conjunction with\n" "the HMAC function, to authenticate received packets.\n" "You can specify a message digest as parameter to\n" "the --auth option.\n\n"); for (nid = 0; nid < 10000; ++nid) { const EVP_MD *digest = EVP_get_digestbynid (nid); if (digest) { printf ("%s %d bit digest size\n", OBJ_nid2sn (nid), EVP_MD_size (digest) * 8); } } printf ("\n");}/* * Enable crypto acceleration, if available */static bool engine_initialized = false; /* GLOBAL */void init_crypto_lib_engine (){ if (!engine_initialized) {#if CRYPTO_ENGINE /* Init available hardware crypto engines. */ msg (M_INFO, "Initializing OpenSSL hardware crypto engine functionality"); ENGINE_load_builtin_engines (); ENGINE_register_all_complete ();#else msg (M_WARN, "Note: OpenSSL hardware crypto engine functionality is not available");#endif engine_initialized = true; }}/* * This routine should have additional OpenSSL crypto library initialisations * used by both crypto and ssl components of OpenVPN. */void init_crypto_lib (){}void uninit_crypto_lib (){#if CRYPTO_ENGINE if (engine_initialized) { ENGINE_cleanup (); engine_initialized = false; }#endif}/* * Random number functions, used in cases where we want * reasonably strong cryptographic random number generation * without depleting our entropy pool. Used for random * IV values and a number of other miscellaneous tasks. */#define NONCE_SECRET_LEN 16static uint8_t nonce_data [SHA_DIGEST_LENGTH + NONCE_SECRET_LEN]; /* GLOBAL */voidprng_init (void){ if (!RAND_bytes (nonce_data, sizeof(nonce_data))) msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for PRNG");}voidprng_bytes (uint8_t *output, int len){ SHA_CTX ctx; mutex_lock_static (L_PRNG); while (len > 0) { const int blen = min_int (len, SHA_DIGEST_LENGTH); SHA1_Init (&ctx); SHA1_Update (&ctx, nonce_data, sizeof (nonce_data)); SHA1_Final (nonce_data, &ctx); memcpy (output, nonce_data, blen); output += blen; len -= blen; } mutex_unlock_static (L_PRNG);}/* an analogue to the random() function, but use prng_bytes */long intget_random(){ long int l; prng_bytes ((unsigned char *)&l, sizeof(l)); if (l < 0) l = -l; return l;}const char *md5sum (uint8_t *buf, int len, int n_print_chars, struct gc_arena *gc){ uint8_t digest[MD5_DIGEST_LENGTH]; MD5 (buf, len, digest); return format_hex (digest, MD5_DIGEST_LENGTH, n_print_chars, gc);}#ifndef USE_SSLvoidinit_ssl_lib (void){ ERR_load_crypto_strings (); OpenSSL_add_all_algorithms (); init_crypto_lib ();}voidfree_ssl_lib (void){ uninit_crypto_lib (); EVP_cleanup (); ERR_free_strings ();}#endif /* USE_SSL */#endif /* USE_CRYPTO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -