⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipsec_doi.c

📁 This a good VPN source
💻 C
📖 第 1 页 / 共 5 页
字号:
/* IPsec DOI and Oakley resolution routines * Copyright (C) 1997 Angelos D. Keromytis. * Copyright (C) 1998-2002  D. Hugh Redelmeier. * Copyright (C) 2003 Michael Richardson <mcr@xelerance.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * for more details. * * RCSID $Id: ipsec_doi.c,v 1.279 2004/12/16 01:20:03 mcr Exp $ */#include <stdio.h>#include <string.h>#include <stddef.h>#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <resolv.h>#include <arpa/nameser.h>	/* missing from <resolv.h> on old systems */#include <sys/queue.h>#include <sys/time.h>		/* for gettimeofday */#include <openswan.h>#include <openswan/ipsec_policy.h>#include "constants.h"#include "defs.h"#include "state.h"#include "id.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#include "connections.h"	/* needs id.h */#include "keys.h"#include "packet.h"#include "demux.h"	/* needs packet.h */#include "adns.h"	/* needs <resolv.h> */#include "dnskey.h"	/* needs keys.h and adns.h */#include "kernel.h"	/* needs connections.h */#include "log.h"#include "cookie.h"#include "server.h"#include "spdb.h"#include "timer.h"#include "rnd.h"#include "ipsec_doi.h"	/* needs demux.h and state.h */#include "whack.h"#include "fetch.h"#include "pkcs.h"#include "asn1.h"#include "sha1.h"#include "md5.h"#include "crypto.h" /* requires sha1.h and md5.h */#include "ike_alg.h"#include "kernel_alg.h"#include "plutoalg.h"#ifdef XAUTH#include "xauth.h"#endif#include "vendor.h"#ifdef NAT_TRAVERSAL#include "nat_traversal.h"#endif#ifdef VIRTUAL_IP#include "virtual.h"#endif#include "dpd.h"#include "pluto_crypt.h"#include "x509more.h"/* OpenPGP Vendor ID needed for interoperability with PGPnet * * Note: it is a NUL-terminated ASCII string, but NUL won't go on the wire. */static char pgp_vendorid[] = "OpenPGP10171";static char dpd_vendorid[] = {0xAF, 0xCA, 0xD7, 0x13, 0x68, 0xA1, 0xF1,          0xC9, 0x6B, 0x86, 0x96, 0xFC, 0x77, 0x57, 0x01, 0x00};/* * continuation used */struct ke_continuation {    struct pluto_crypto_req_cont ke_pcrc;    struct msg_digest           *md;};struct qke_continuation {    struct pluto_crypto_req_cont qke_pcrc;    struct state                *st;            /* need to use abstract # */    struct state                *isakmp_sa;     /* used in initiator */    so_serial_t                  replacing;    struct msg_digest           *md;            /* used in responder */};/** tools for sending Pluto Vendor ID. */#ifdef PLUTO_SENDS_VENDORID#define SEND_PLUTO_VID	1#else /* !PLUTO_SENDS_VENDORID */#define SEND_PLUTO_VID	0#endif /* !PLUTO_SENDS_VENDORID *//* Pluto's Vendor ID * * Note: it is a NUL-terminated ASCII string, but NUL won't go on the wire. */#define PLUTO_VENDORID_SIZE 12static char pluto_vendorid[PLUTO_VENDORID_SIZE + 1];const char *init_pluto_vendorid(void){    MD5_CTX hc;    unsigned char hash[MD5_DIGEST_SIZE];    const unsigned char *v = ipsec_version_string();    int i;    osMD5Init(&hc);    osMD5Update(&hc, v, strlen(v));    osMD5Update(&hc, compile_time_interop_options	, strlen(compile_time_interop_options));    osMD5Final(hash, &hc);    pluto_vendorid[0] = 'O';	/* Opportunistic Encryption Rules */    pluto_vendorid[1] = 'E';#if PLUTO_VENDORID_SIZE - 2 <= MD5_DIGEST_SIZE    /* truncate hash to fit our vendor ID */    memcpy(pluto_vendorid + 2, hash, PLUTO_VENDORID_SIZE - 2);#else    /* pad to fill our vendor ID */    memcpy(pluto_vendorid + 2, hash, MD5_DIGEST_SIZE);    memset(pluto_vendorid + 2 + MD5_DIGEST_SIZE, '\0'	, PLUTO_VENDORID_SIZE - 2 - MD5_DIGEST_SIZE);#endif    /* Make it printable!  Hahaha - MCR */    for (i = 2; i < PLUTO_VENDORID_SIZE; i++)    {	/* Reset bit 7, force bit 6.  Puts it into 64-127 range */	pluto_vendorid[i] &= 0x7f;	pluto_vendorid[i] |= 0x40;    }    pluto_vendorid[PLUTO_VENDORID_SIZE] = '\0';    return pluto_vendorid;}typedef stf_status initiator_function(int whack_sock				      , struct connection *c				      , struct state *predecessor				      , lset_t policy				      , unsigned long try				      , enum crypto_importance importance);/* MAGIC: perform f, a function that returns notification_t * and return from the ENCLOSING stf_status returning function if it fails. */#define RETURN_STF_FAILURE2(f, xf)					\    { int r = (f); if (r != NOTHING_WRONG) { \	  if((xf)!=NULL) pfree(xf);	     \	  return STF_FAIL + r; }}#define RETURN_STF_FAILURE(f) RETURN_STF_FAILURE2(f, NULL)/* create output HDR as replica of input HDR */voidecho_hdr(struct msg_digest *md, bool enc, u_int8_t np){    struct isakmp_hdr r_hdr = md->hdr;	/* mostly same as incoming header */    r_hdr.isa_flags &= ~ISAKMP_FLAG_COMMIT;	/* we won't ever turn on this bit */    if (enc)	r_hdr.isa_flags |= ISAKMP_FLAG_ENCRYPTION;    /* some day, we may have to set r_hdr.isa_version */    r_hdr.isa_np = np;    if (!out_struct(&r_hdr, &isakmp_hdr_desc, &md->reply, &md->rbody)) {	impossible();	/* surely must have room and be well-formed */    }}/** Compute DH shared secret from our local secret and the peer's public value. * We make the leap that the length should be that of the group * (see quoted passage at start of ACCEPT_KE). */static voidcompute_dh_shared(struct state *st, const chunk_t g, const struct oakley_group_desc *group){    MP_INT mp_g, mp_shared;    struct timeval tv0, tv1;    unsigned long tv_diff;    gettimeofday(&tv0, NULL);    passert(st->st_sec_in_use);    n_to_mpz(&mp_g, g.ptr, g.len);    mpz_init(&mp_shared);    mpz_powm(&mp_shared, &mp_g, &st->st_sec, group->modulus);    mpz_clear(&mp_g);    freeanychunk(st->st_shared);	/* happens in odd error cases */    st->st_shared = mpz_to_n(&mp_shared, group->bytes);    mpz_clear(&mp_shared);    gettimeofday(&tv1, NULL);    tv_diff=(tv1.tv_sec  - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec);    DBG(DBG_CRYPT,     	DBG_log("compute_dh_shared(): time elapsed (%s): %ld usec"		, enum_show(&oakley_group_names, st->st_oakley.group->group)		, tv_diff);       );    /* if took more than 200 msec ... */    if (tv_diff > 200000) {	loglog(RC_LOG_SERIOUS, "WARNING: compute_dh_shared(): for %s took "			"%ld usec"		, enum_show(&oakley_group_names, st->st_oakley.group->group)		, tv_diff);    }    DBG_cond_dump_chunk(DBG_CRYPT, "DH shared secret:\n", st->st_shared);}#if 0/** if we haven't already done so, compute a local DH secret (st->st_sec) and * the corresponding public value (g).  This is emitted as a KE payload. */static boolbuild_and_ship_KE(struct state *st, chunk_t *g, const struct oakley_group_desc *group, pb_stream *outs, u_int8_t np){    if (!st->st_sec_in_use)    {	u_char tmp[LOCALSECRETSIZE];	MP_INT mp_g;	get_rnd_bytes(tmp, LOCALSECRETSIZE);	st->st_sec_in_use = TRUE;	n_to_mpz(&st->st_sec, tmp, LOCALSECRETSIZE);	mpz_init(&mp_g);	mpz_powm(&mp_g, &groupgenerator, &st->st_sec, group->modulus);	freeanychunk(*g);	/* happens in odd error cases */	*g = mpz_to_n(&mp_g, group->bytes);	mpz_clear(&mp_g);	DBG(DBG_CRYPT,	    DBG_dump("Local DH secret:\n", tmp, LOCALSECRETSIZE);	    DBG_dump_chunk("Public DH value sent:\n", *g));    }    return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value");}#endif/* * package up the calculate KE value, and emit it as a KE payload. */static boolship_KE(struct state *st	, struct pluto_crypto_req *r	, chunk_t *g	, pb_stream *outs, u_int8_t np){    struct pcr_kenonce *kn = &r->pcr_d.kn;    if (!st->st_sec_in_use)    {	st->st_sec_in_use = TRUE;	freeanychunk(*g);	/* happens in odd error cases */	clonetochunk(*g, wire_chunk_ptr(kn, &(kn->gi))		     , kn->gi.len, "saved gi value");	n_to_mpz(&st->st_sec		 , wire_chunk_ptr(kn, &(kn->secret))		 , kn->secret.len);    }    return out_generic_chunk(np, &isakmp_keyex_desc, outs, *g, "keyex value");}/* accept_ke * * Check and accept DH public value (Gi or Gr) from peer's message. * According to RFC2409 "The Internet key exchange (IKE)" 5: *  The Diffie-Hellman public value passed in a KE payload, in either *  a phase 1 or phase 2 exchange, MUST be the length of the negotiated *  Diffie-Hellman group enforced, if necessary, by pre-pending the *  value with zeros. */static notification_taccept_KE(chunk_t *dest, const char *val_name, const struct oakley_group_desc *gr, pb_stream *pbs){    if (pbs_left(pbs) != gr->bytes)    {	loglog(RC_LOG_SERIOUS, "KE has %u byte DH public value; %u required"	    , (unsigned) pbs_left(pbs), (unsigned) gr->bytes);	/* XXX Could send notification back */	return INVALID_KEY_INFORMATION;    }    clonereplacechunk(*dest, pbs->cur, pbs_left(pbs), val_name);    DBG_cond_dump_chunk(DBG_CRYPT, "DH public value received:\n", *dest);    return NOTHING_WRONG;}/* accept_PFS_KE * * Check and accept optional Quick Mode KE payload for PFS. * Extends ACCEPT_PFS to check whether KE is allowed or required. */static notification_taccept_PFS_KE(struct msg_digest *md, chunk_t *dest, const char *val_name, const char *msg_name){    struct state *st = md->st;    struct payload_digest *const ke_pd = md->chain[ISAKMP_NEXT_KE];    if (ke_pd == NULL)    {	if (st->st_pfs_group != NULL)	{	    loglog(RC_LOG_SERIOUS, "missing KE payload in %s message", msg_name);	    return INVALID_KEY_INFORMATION;	}    }    else    {	if (st->st_pfs_group == NULL)	{	    loglog(RC_LOG_SERIOUS, "%s message KE payload requires a GROUP_DESCRIPTION attribute in SA"		, msg_name);	    return INVALID_KEY_INFORMATION;	}	if (ke_pd->next != NULL)	{	    loglog(RC_LOG_SERIOUS, "%s message contains several KE payloads; we accept at most one", msg_name);	    return INVALID_KEY_INFORMATION;	/* ??? */	}	return accept_KE(dest, val_name, st->st_pfs_group, &ke_pd->pbs);    }    return NOTHING_WRONG;}#if 0static boolbuild_and_ship_nonce(chunk_t *n, pb_stream *outs, u_int8_t np		     , const char *name){    freeanychunk(*n);    setchunk(*n, alloc_bytes(DEFAULT_NONCE_SIZE, name), DEFAULT_NONCE_SIZE);    get_rnd_bytes(n->ptr, DEFAULT_NONCE_SIZE);    return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, name);}#endifstatic boolship_nonce(chunk_t *n, struct pluto_crypto_req *r	   , pb_stream *outs, u_int8_t np	   , const char *name){    struct pcr_kenonce *kn = &r->pcr_d.kn;    freeanychunk(*n);    clonetochunk(*n, wire_chunk_ptr(kn, &(kn->n))		 , DEFAULT_NONCE_SIZE, "initiator nonce");    return out_generic_chunk(np, &isakmp_nonce_desc, outs, *n, name);}/* Send a notification to the peer.  We could decide * whether to send the notification, based on the type and the * destination, if we care to. */static voidsend_notification(struct state *sndst, u_int16_t type, struct state *encst,    msgid_t msgid, u_char *icookie, u_char *rcookie,    u_char *spi, size_t spisize, u_char protoid){    u_char buffer[1024];    pb_stream pbs, r_hdr_pbs;    u_char *r_hashval, *r_hash_start;    passert((sndst) && (sndst->st_connection));    switch(type) {    case PAYLOAD_MALFORMED:	sndst->hidden_variables.st_malformed_sent++;	if(sndst->hidden_variables.st_malformed_sent > MAXIMUM_MALFORMED_NOTIFY) {	    openswan_log("too many (%d) malformed payloads. Deleting state"			 , sndst->hidden_variables.st_malformed_sent);	    delete_state(sndst);	    return;	}	/*	 * do not encrypt notification, since #1 reason for malformed	 * payload is that the keys are all messed up.	 */	encst = NULL;	break;	    case INVALID_FLAGS:	/*	 * invalid flags usually includes encryption flags, so do not	 * send encrypted.	 */	encst = NULL;	break;    }        if(encst!=NULL && !IS_ISAKMP_ENCRYPTED(encst->st_state)) {	encst = NULL;    }    openswan_log("sending %snotification %s to %s:%u"	, encst ? "encrypted " : ""	, enum_name(&ipsec_notification_names, type)	, ip_str(&sndst->st_connection->spd.that.host_addr)	, (unsigned)sndst->st_connection->spd.that.host_port);    memset(buffer, 0, sizeof(buffer));    init_pbs(&pbs, buffer, sizeof(buffer), "notification msg");    /* HDR* */    {	struct isakmp_hdr hdr;	hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;	hdr.isa_np = encst ? ISAKMP_NEXT_HASH : ISAKMP_NEXT_N;	hdr.isa_xchg = ISAKMP_XCHG_INFO;	hdr.isa_msgid = msgid;	hdr.isa_flags = encst ? ISAKMP_FLAG_ENCRYPTION : 0;	if (icookie)	    memcpy(hdr.isa_icookie, icookie, COOKIE_SIZE);	if (rcookie)	    memcpy(hdr.isa_rcookie, rcookie, COOKIE_SIZE);	if (!out_struct(&hdr, &isakmp_hdr_desc, &pbs, &r_hdr_pbs))	    impossible();    }    /* HASH -- value to be filled later */    if (encst)    {	pb_stream hash_pbs;	if (!out_generic(ISAKMP_NEXT_N, &isakmp_hash_desc, &r_hdr_pbs,	    &hash_pbs))	    impossible();	r_hashval = hash_pbs.cur;  /* remember where to plant value */	if (!out_zero(	    encst->st_oakley.hasher->hash_digest_len,	    &hash_pbs, "HASH(1)"))	    impossible();	close_output_pbs(&hash_pbs);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -