📄 crypto.c
字号:
/* make sure IV changed */ if (!memcmp (iv_save, co->iv, EVP_MAX_IV_LENGTH)) msg (M_FATAL, "IV Collision: before:%s after:%s", format_hex (iv_save, EVP_MAX_IV_LENGTH, 0), format_hex (co->iv, EVP_MAX_IV_LENGTH, 0)); /* decrypt */ openvpn_decrypt (&buf, decrypt_workspace, co, frame, current); /* 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, "OpenVPN crypto self-test mode SUCCEEDED.");}#ifdef USE_SSLvoidget_tls_handshake_key (const struct key_type *key_type, struct key_ctx_bi *ctx, const char *passphrase_file){ if (passphrase_file && key_type->hmac_length) { struct key key; struct key_type kt = *key_type; /* for control channel we are only authenticating, not encrypting */ kt.cipher_length = 0; kt.cipher = NULL; /* get key material for hmac */ { int digest_len; uint8_t digest[MAX_HMAC_KEY_LENGTH]; EVP_MD_CTX md; CLEAR (key); EVP_DigestInit (&md, kt.digest); /* read passphrase file */ { const int min_passphrase_size = 8; uint8_t buf[512]; 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, digest, &digest_len); ASSERT (digest_len == kt.hmac_length); memcpy (key.hmac, digest, digest_len); CLEAR (digest); EVP_MD_CTX_cleanup (&md); } /* use same hmac key in both directions */ init_key_ctx (&ctx->encrypt, &key, &kt, DO_ENCRYPT, "Outgoing Control Channel Authentication"); init_key_ctx (&ctx->decrypt, &key, &kt, DO_DECRYPT, "Incoming Control Channel Authentication"); CLEAR (key); } else { CLEAR (*ctx); }}#endif/* header and footer for static key file */static const char static_key_head[] = "-----BEGIN OpenVPN Static key V1-----";static const char static_key_foot[] = "-----END OpenVPN Static key V1-----";static const char printable_char_fmt[] = "Non-Hex character ('%c') found at line %d in key file %s (%d/%d bytes found/required)";static const char unprintable_char_fmt[] = "Non-Hex, unprintable character (0x%02x) found at line %d in key file %s (%d/%d bytes found/required)";/* read key from file */voidread_key_file (struct key *key, const char *filename){ const int gc_level = gc_new_level (); struct buffer in = alloc_buf_gc (512); int state = 0; uint8_t* out = (uint8_t*) key; int count = 0; uint8_t hex_byte[3] = {0, 0, 0}; int hb_index = 0; int line_num = 1; int line_index = 0; int matchlen = 0; const int headlen = strlen(static_key_head); const int keylen = sizeof (*key); int fd, size; fd = open (filename, O_RDONLY); if (fd == -1) msg (M_ERR, "Cannot open shared secret file %s", filename); while (size = read (fd, in.data, in.capacity)) { const char *cp = in.data; while (size) { const char c = *cp; /* msg (M_INFO, "char='%c' state=%d line_num=%d line_index=%d matchlen=%d", c, state, line_num, line_index, matchlen); */ if (c == '\n') { line_index = 0; ++line_num; } else { /* found header line? */ if (state == 0 && !line_index) { if (matchlen == headlen) state = 1; matchlen = 0; } /* compare read chars with header line */ if (state == 0) { if (line_index < headlen && c == static_key_head[line_index]) ++matchlen; } /* reading key */ if (state == 1) { if (isxdigit(c)) { ASSERT(hb_index < 2); hex_byte[hb_index++] = c; if (hb_index == 2) { unsigned int u; ASSERT(sscanf(hex_byte, "%x", &u) == 1); *out++ = u; hb_index = 0; if (++count == keylen) state = 2; } } else if (isspace(c)) ; else { msg (M_FATAL, (isprint (c) ? printable_char_fmt : unprintable_char_fmt), c, line_num, filename, count, keylen); } } ++line_index; } ++cp; --size; } } close (fd); if (state != 2) msg (M_ERR, "Key not found in file %s (%d/%d bytes found/required)", filename, count, keylen); /* zero file read buffer */ memset(in.data, 0, in.capacity); warn_if_group_others_accessible (filename); /* pop our garbage collection level */ gc_free_level (gc_level);}/* write key to file */voidwrite_key_file (const struct key *key, const char *filename){ int fd, size, len; char* fmt; const int gc_level = gc_new_level (); struct buffer out = alloc_buf_gc (512); /* open key file */ fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU); if (fd == -1) msg (M_ERR, "Cannot open shared secret file %s for write", filename); /* format key as ascii */ fmt = format_hex_ex ((const uint8_t*)key, sizeof (*key), 0, 8, "\n"); buf_printf (&out, "%s\n", static_key_head); buf_printf (&out, "%s\n", fmt); buf_printf (&out, "%s\n", static_key_foot); /* write data to file */ len = strlen (BPTR(&out)); size = write (fd, BPTR(&out), len); if (size != len) msg (M_ERR, "Write error on shared secret file %s", filename); if (close (fd)) msg (M_ERR, "Close error on shared secret file %s", filename); /* zero memory that held keys (memory will be freed by garbage collector) */ memset (BPTR(&out), 0, len); memset (fmt, 0, strlen(fmt)); /* pop our garbage collection level */ gc_free_level (gc_level);}/* 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 OpenVPN. 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 || mode == EVP_CIPH_CFB_MODE || mode == EVP_CIPH_OFB_MODE) 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" "OpenVPN. 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");}/* * This routine should have additional OpenSSL crypto library initialisations * used by both crypto and ssl components of OpenVPN. */void init_crypto_lib (){}#ifndef USE_SSLvoidinit_ssl_lib (){ ERR_load_crypto_strings (); OpenSSL_add_all_algorithms (); init_crypto_lib();}voidfree_ssl_lib (){ EVP_cleanup (); ERR_free_strings ();}#endif /* USE_SSL */#endif /* USE_CRYPTO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -