📄 crypto.c
字号:
if (warn) msg (M_WARN, "******* WARNING *******: null MAC specified, no authentication will be used"); }}const char *kt_cipher_name (const struct key_type *kt){ if (kt->cipher) return EVP_CIPHER_name (kt->cipher); else return "[null-cipher]";}const char *kt_digest_name (const struct key_type *kt){ if (kt->digest) return EVP_MD_name (kt->digest); else return "[null-digest]";}intkt_key_size (const struct key_type *kt){ if (kt->cipher_length) return kt->cipher_length * 8; else if (kt->cipher) return EVP_CIPHER_key_length (kt->cipher) * 8; else return 0;}/* given a key and key_type, build a key_ctx */voidinit_key_ctx (struct key_ctx *ctx, struct key *key, const struct key_type *kt, int enc, const char *prefix){ CLEAR (*ctx); if (kt->cipher && kt->cipher_length > 0) { ALLOC_OBJ (ctx->cipher, EVP_CIPHER_CTX); init_cipher (ctx->cipher, kt->cipher, key, kt, enc, prefix); } if (kt->digest && kt->hmac_length > 0) { ALLOC_OBJ (ctx->hmac, HMAC_CTX); init_hmac (ctx->hmac, kt->digest, key, kt, prefix); }}voidfree_key_ctx (struct key_ctx *ctx){ if (ctx->cipher) { EVP_CIPHER_CTX_cleanup (ctx->cipher); free (ctx->cipher); ctx->cipher = NULL; } if (ctx->hmac) { HMAC_CTX_cleanup (ctx->hmac); free (ctx->hmac); ctx->hmac = NULL; }}voidfree_key_ctx_bi (struct key_ctx_bi *ctx){ free_key_ctx(&ctx->encrypt); free_key_ctx(&ctx->decrypt);}/* * Return number of DES cblocks for the current * key type or 0 if not a DES cipher. */static intn_DES_cblocks (const struct key_type *kt){ int ret = 0; const char *name = OBJ_nid2sn (EVP_CIPHER_nid (kt->cipher)); if (name) { if (!strncmp (name, "DES-", 4)) { ret = EVP_CIPHER_key_length (kt->cipher) / sizeof (DES_cblock); } else if (!strncmp (name, "DESX-", 5)) { ret = 1; } } msg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret); return ret;}static boolcheck_key_DES (struct key *key, const struct key_type *kt, int ndc){ int i; struct buffer b; buf_set_read (&b, key->cipher, kt->cipher_length); for (i = 0; i < ndc; ++i) { DES_cblock *dc = (DES_cblock*) buf_read_alloc (&b, sizeof (DES_cblock)); if (!dc) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material"); return false; } if (DES_is_weak_key(dc)) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected"); return false; } if (!DES_check_key_parity (dc)) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected"); return false; } } return true;}static voidfixup_key_DES (struct key *key, const struct key_type *kt, int ndc){ int i; struct buffer b; buf_set_read (&b, key->cipher, kt->cipher_length); for (i = 0; i < ndc; ++i) { DES_cblock *dc = (DES_cblock*) buf_read_alloc(&b, sizeof(DES_cblock)); if (!dc) { msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material"); return; } DES_set_odd_parity (dc); }}static boolkey_is_zero (struct key *key, const struct key_type *kt){ int i; for (i = 0; i < kt->cipher_length; ++i) if (key->cipher[i]) return false; msg (D_CRYPT_ERRORS, "CRYPTO INFO: WARNING: zero key detected"); return true;}/* * Make sure that cipher key is a valid key for current key_type. */boolcheck_key (struct key *key, const struct key_type *kt){ if (kt->cipher) { /* * Check for zero key */ if (key_is_zero(key, kt)) return false; /* * Check for weak or semi-weak DES keys. */ { const int ndc = n_DES_cblocks (kt); if (ndc) return check_key_DES (key, kt, ndc); else return true; } } return true;}/* * Make safe mutations to key to ensure it is valid, * such as ensuring correct parity on DES keys. * * This routine cannot guarantee it will generate a good * key. You must always call check_key after this routine * to make sure. */ voidfixup_key (struct key *key, const struct key_type *kt){ struct gc_arena gc = gc_new (); if (kt->cipher) { const struct key orig = *key; const int ndc = n_DES_cblocks (kt); if (ndc) fixup_key_DES (key, kt, ndc); if (check_debug_level (D_CRYPTO_DEBUG)) { if (memcmp (orig.cipher, key->cipher, kt->cipher_length)) msg (D_CRYPTO_DEBUG, "CRYPTO INFO: fixup_key: before=%s after=%s", format_hex (orig.cipher, kt->cipher_length, 0, &gc), format_hex (key->cipher, kt->cipher_length, 0, &gc)); } } gc_free (&gc);}voidcheck_replay_iv_consistency (const struct key_type *kt, bool packet_id, bool use_iv){ if (cfb_ofb_mode (kt) && !(packet_id && use_iv)) msg (M_FATAL, "--no-replay or --no-iv cannot be used with a CFB or OFB mode cipher");}boolcfb_ofb_mode (const struct key_type* kt){ if (kt->cipher) { const unsigned int mode = EVP_CIPHER_mode (kt->cipher); return mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE; } else return false;}/* * Generate a random key. If key_type is provided, make * sure generated key is valid for key_type. */voidgenerate_key_random (struct key *key, const struct key_type *kt){ int cipher_len = MAX_CIPHER_KEY_LENGTH; int hmac_len = MAX_HMAC_KEY_LENGTH; struct gc_arena gc = gc_new (); do { CLEAR (*key); if (kt) { if (kt->cipher && kt->cipher_length > 0 && kt->cipher_length <= cipher_len) cipher_len = kt->cipher_length; if (kt->digest && kt->hmac_length > 0 && kt->hmac_length <= hmac_len) hmac_len = kt->hmac_length; } if (!RAND_bytes (key->cipher, cipher_len) || !RAND_bytes (key->hmac, hmac_len)) msg (M_FATAL, "ERROR: Random number generator cannot obtain entropy for key generation"); msg (D_SHOW_KEY_SOURCE, "Cipher source entropy: %s", format_hex (key->cipher, cipher_len, 0, &gc)); msg (D_SHOW_KEY_SOURCE, "HMAC source entropy: %s", format_hex (key->hmac, hmac_len, 0, &gc)); if (kt) fixup_key (key, kt); } while (kt && !check_key (key, kt)); gc_free (&gc);}/* * Print key material */voidkey2_print (const struct key2* k, const struct key_type *kt, const char* prefix0, const char* prefix1){ struct gc_arena gc = gc_new (); ASSERT (k->n == 2); msg (D_SHOW_KEY_SOURCE, "%s (cipher): %s", prefix0, format_hex (k->keys[0].cipher, kt->cipher_length, 0, &gc)); msg (D_SHOW_KEY_SOURCE, "%s (hmac): %s", prefix0, format_hex (k->keys[0].hmac, kt->hmac_length, 0, &gc)); msg (D_SHOW_KEY_SOURCE, "%s (cipher): %s", prefix1, format_hex (k->keys[1].cipher, kt->cipher_length, 0, &gc)); msg (D_SHOW_KEY_SOURCE, "%s (hmac): %s", prefix1, format_hex (k->keys[1].hmac, kt->hmac_length, 0, &gc)); gc_free (&gc);}voidtest_crypto (const struct crypto_options *co, struct frame* frame){ int i, j; struct gc_arena gc = gc_new (); struct buffer src = alloc_buf_gc (TUN_MTU_SIZE (frame), &gc); struct buffer work = alloc_buf_gc (BUF_SIZE (frame), &gc); struct buffer encrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc); struct buffer decrypt_workspace = alloc_buf_gc (BUF_SIZE (frame), &gc); struct buffer buf = clear_buf(); /* init work */ ASSERT (buf_init (&work, FRAME_HEADROOM (frame))); msg (M_INFO, "Entering " PACKAGE_NAME " crypto self-test mode."); for (i = 1; i <= TUN_MTU_SIZE (frame); ++i) { update_time (); msg (M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i); /* * Load src with random data. */ ASSERT (buf_init (&src, 0)); ASSERT (i <= src.capacity); src.len = i; ASSERT (RAND_pseudo_bytes (BPTR (&src), BLEN (&src))); /* copy source to input buf */ buf = work; memcpy (buf_write_alloc (&buf, BLEN (&src)), BPTR (&src), BLEN (&src)); /* encrypt */ openvpn_encrypt (&buf, encrypt_workspace, co, frame); /* decrypt */ openvpn_decrypt (&buf, decrypt_workspace, co, frame); /* compare */ if (buf.len != src.len) msg (M_FATAL, "SELF TEST FAILED, src.len=%d buf.len=%d", src.len, buf.len); for (j = 0; j < i; ++j) { const uint8_t in = *(BPTR (&src) + j); const uint8_t out = *(BPTR (&buf) + j); if (in != out) msg (M_FATAL, "SELF TEST FAILED, pos=%d in=%d out=%d", j, in, out); } } msg (M_INFO, PACKAGE_NAME " crypto self-test mode SUCCEEDED."); gc_free (&gc);}#ifdef USE_SSLvoidget_tls_handshake_key (const struct key_type *key_type, struct key_ctx_bi *ctx, const char *passphrase_file, bool key_direction){ if (passphrase_file && key_type->hmac_length) { struct key2 key2; struct key_type kt = *key_type; struct key_direction_state kds; /* for control channel we are only authenticating, not encrypting */ kt.cipher_length = 0; kt.cipher = NULL; /* first try to parse as an OpenVPN static key file */ read_key_file (&key2, passphrase_file, false); /* succeeded? */ if (key2.n == 2) { msg (M_INFO, "Control Channel Authentication: using '%s' as a " PACKAGE_NAME " static key file", passphrase_file); } else { int hash_size; CLEAR (key2); /* failed, now try to get hash from a freeform file */ hash_size = read_passphrase_hash (passphrase_file, kt.digest, key2.keys[0].hmac, MAX_HMAC_KEY_LENGTH); ASSERT (hash_size == kt.hmac_length); /* suceeded */ key2.n = 1; msg (M_INFO, "Control Channel Authentication: using '%s' as a free-form passphrase file", passphrase_file); } /* handle key direction */ key_direction_state_init (&kds, key_direction); must_have_n_keys (passphrase_file, "tls-auth", &key2, kds.need_keys); /* initialize hmac key in both directions */ init_key_ctx (&ctx->encrypt, &key2.keys[kds.out_key], &kt, DO_ENCRYPT, "Outgoing Control Channel Authentication"); init_key_ctx (&ctx->decrypt, &key2.keys[kds.in_key], &kt, DO_DECRYPT, "Incoming Control Channel Authentication"); CLEAR (key2); } else { CLEAR (*ctx); }}#endif/* header and footer for static key file */static const char static_key_head[] = "-----BEGIN " PACKAGE_NAME " Static key V1-----";static const char static_key_foot[] = "-----END " PACKAGE_NAME " Static key V1-----";static const char printable_char_fmt[] = "Non-Hex character ('%c') found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)";static const char unprintable_char_fmt[] = "Non-Hex, unprintable character (0x%02x) found at line %d in key file '%s' (%d/%d/%d bytes found/min/max)";/* read key from file */voidread_key_file (struct key2 *key2, const char *filename, bool must_succeed){ struct gc_arena gc = gc_new (); struct buffer in = alloc_buf_gc (64, &gc); int fd, size; uint8_t hex_byte[3] = {0, 0, 0}; /* parse info */ int hb_index = 0; int line_num = 1; int line_index = 0; int match = 0; /* output */ uint8_t* out = (uint8_t*) &key2->keys; const int keylen = sizeof (key2->keys); int count = 0; /* parse states */# define PARSE_INITIAL 0# define PARSE_HEAD 1# define PARSE_DATA 2# define PARSE_DATA_COMPLETE 3# define PARSE_FOOT 4# define PARSE_FINISHED 5 int state = PARSE_INITIAL; /* constants */ const int hlen = strlen (static_key_head); const int flen = strlen (static_key_foot); const int onekeylen = sizeof (key2->keys[0]); CLEAR (*key2); fd = open (filename, O_RDONLY); if (fd == -1) msg (M_ERR, "Cannot open file key file '%s'", filename); while ((size = read (fd, in.data, in.capacity))) { const char *cp = (char *)in.data; while (size) { const char c = *cp;#if 0 msg (M_INFO, "char='%c' s=%d ln=%d li=%d m=%d c=%d", c, state, line_num, line_index, match, count);#endif if (c == '\n') { line_index = match = 0; ++line_num; } else { /* first char of new line */ if (!line_index) { /* first char of line after header line? */ if (state == PARSE_HEAD) state = PARSE_DATA; /* first char of footer */ if ((state == PARSE_DATA || state == PARSE_DATA_COMPLETE) && c == '-') state = PARSE_FOOT; } /* compare read chars with header line */ if (state == PARSE_INITIAL) { if (line_index < hlen && c == static_key_head[line_index]) { if (++match == hlen) state = PARSE_HEAD; } } /* compare read chars with footer line */ if (state == PARSE_FOOT) { if (line_index < flen && c == static_key_foot[line_index]) { if (++match == flen)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -