crypto.c
来自「OpenVPN -- A Secure tunneling daemon」· C语言 代码 · 共 1,157 行 · 第 1/3 页
C
1,157 行
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 */ { unsigned 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 = (char *)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((const char *)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_IRUSR | S_IWUSR); 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 ((char *)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 (){}/* an analogue to the random() function, but use OpenSSL function */long intget_random(){ long int l; ASSERT (RAND_pseudo_bytes ((unsigned char *)&l, sizeof(l))); if (l < 0) l = -l; return l;}const char *md5sum(uint8_t *buf, int len){ uint8_t digest[MD5_DIGEST_LENGTH]; MD5 (buf, len, digest); return format_hex (digest, MD5_DIGEST_LENGTH, 0);}#ifndef USE_SSLvoidinit_ssl_lib (void){ ERR_load_crypto_strings (); OpenSSL_add_all_algorithms (); init_crypto_lib();}voidfree_ssl_lib (void){ EVP_cleanup (); ERR_free_strings ();}#endif /* USE_SSL */#endif /* USE_CRYPTO */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?