This commit is contained in:
Martin Willi
2006-04-28 10:51:19 +00:00
parent 51c3484a9f
commit 1029d84d23
514 changed files with 2 additions and 2 deletions
+3
View File
@@ -0,0 +1,3 @@
_pluto_adns
pluto
whack
+1095
View File
File diff suppressed because it is too large Load Diff
+127
View File
@@ -0,0 +1,127 @@
Notes on Pluto Conventions
==========================
RCSID $Id: PLUTO-CONVENTIONS,v 1.1 2004/03/15 20:35:28 as Exp $
Pluto has its own stylistic conventions. They are fairly easily
inferred by reading the code.
- sample formatting:
void
fun(char *s)
{
if (s == NULL)
{
return "";
}
else
{
switch (*s)
{
default:
s++;
/* fall through */
case '\0':
return s;
}
}
}
- a function definition has its function identifier at the margin
- indentation is in steps of 4 columns (tabstops are every 8 columns)
- try to keep lines shorter than 80 columns
- space should be canonical:
+ no line should have trailing whitespace
+ leading whitespace should use tabs where possible
+ indentation should be precise
+ there should be no empty lines at the end of a file.
- braces go on their own line, indented the same as the start of what they are part of
- switch labels are indented the same as the enclosing braces
- if a case falls through, say so explicitly
- spaces follow control flow reserved words (but not function names)
- the operand of return need not be parenthesized
- be careful with types. For example, use size_t and ssize_t.
Use const wherever possible.
- we pretend that C has a strong boolean type.
We actually define bool with constants TRUE and FALSE.
Other types cannot be used as the complete expression in a test.
Hence:
if (s == NULL)
One exception: lset_t values can be treated as booleans
(technically they are, in the original sense of the word)
- memsetting a pointer to binary zero is not guaranteed to make it NULL
- side-effects of expressions are to be avoided.
BAD: if (i++ == 9)
OK: i++;
- variables are to have as small a scope as is possible.
Move definitions into inner blocks whenever possible.
Often initializing definitions become possible and are clearer.
- within a block that has declarations, separate the declarations from
the other statements with a blank line.
- "magic numbers" are suspect. Most integers in code stand for something.
They should be given a name, and that name used consistently.
- don't use malloc/free -- use the wrappers (see defs.h)
- it is good to put comments on #else and #endif to show what
they match with. I use ! to indicate the sense of the test:
#ifdef CRUD
#else /* !CRUD */
#endif /* !CRUD */
#ifndef CRUD
#else /* CRUD */
#endif /* CRUD */
- all functions and variables that are exported from a .c file should
be declared in that file's header file. Because the .c includes the
header, the declaration and the definition will be checked by the
compiler. There is almost no excuse for the "extern" keyword
in a .c file.
- when lines are too long and expressions are to be broken, try to
break just before a binary operator. The outermost binary operator
is preferred. This is perhaps the most unconventional convention.
It allows the structure of code to be evident from a scan of the
left margin. Example:
if (next_step == vos_his_client
&& sameaddr(&c->spd.that.host_addr, &his_client))
next_step = vos_done;
and
p = oppo_instantiate(p, &c->spd.that.host_addr, &c->spd.that.id
, NULL, &our_client, &his_client);
Note the different indentation of the continuations. The continuation
of a control flow statement is not indented but other continuations are.
- Never put two statements on one line.
REALLY BAD: if (cat);
Exception: some macro definitions.
- C preprocessor macros are implemented by a kind of textual substitution.
Be sure to put parentheses around references to macro arguments and
around the whole macro body. If the body is meant to be a statement,
put braces around it instead.
#define RETURN_STF_FAILURE(f) \
{ int r = (f); if (r != NOTHING_WRONG) return STF_FAIL + r; }
- adding #include statements adds dependencies. The Makefile should be
changed to reflect them. Target "makedepend" will try to list dependencies
in a way suitable for pasting into Makefile
+129
View File
@@ -0,0 +1,129 @@
Pluto TODO list
===============
RCSID $Id: TODO,v 1.1 2004/03/15 20:35:28 as Exp $
- should all log entries that are for errors say ERROR?
- Add a "plug-in" facility so that others can add features without
changing the mainline code. This is how X509/LDAP/biometric stuff
might be added.
- (internal change only) routines for outputting payloads should plug
"np" into the previous payload so that a payload generating routine
need not know what the next payload will be. This may be more bother
than it is worth.
- notifications, in and out
+ delete
+ first contact
+ last contact? (not part of drafts, but would be nice)
- Make DNS usage for asynchronous (non-blocking)
+ looking up KEY and TXT records during negotiation
+ perhaps not for whack command arguments and ipsec.secrets since the
library code uses gethostbyname
- check that ipsec auto and whack to agree on what is worth reporting
- Should Pluto (rather than ipsec manual) install %passthrough conns?
That way Pluto would know of them.
- For responding to Road Warriors, how can we decide if the RW has
gone away? The rekeying event is perhaps too imprecise. Even if
rekeying event is good enough, how do we know if the route should be
torn down? Perhaps limiting a Phase 1 ID to one IP address would
help (limiting a client subnet to one peer already helps). Perhaps
(in some rate-limited way) we can take an ICMP host unreachable
as a hint to do some authenticated and reliable probe.
- it is annoying that Pluto and auto have different models for public keys.
+ auto specifies one per connection
+ Pluto allows one to be specified per id
Two connections with the same id are going to use the same key:
the one of the last conn to be added!
I think auto ought to be fixed. It is hard for Pluto to warn when
there is a conflict since the deletion of a connection doesn't
prompt auto to tell pluto to delete the public key.
- different connections with the same host IP addresses are randomly
interchangeable until the ID payload is received. At least for the
Responder case (and eventually for the opportunistic Initiator).
Worse, all Road Warriors must be considered to have the
indistinguishable IP addresses. This affects ISAKMP SA negotiation.
Currently, there is little flexibility in this negotiation, so the
problem is limited to the specification of acceptable authentication
method(s). Correct, but more work than seems worthwhile, would be
to select the conn based on what is proposed.
Warning about such confusion at connection definition time isn't great
because there is no confusion when explicitly initiated (a particular
conn is specified). Warning for a Road Warrior conn is possible
since it cannot be initiated (and has been implemented).
- characterize and ameliorate DOS attacks. Lots of rate limiting.
- look at John Denker's wish list: http://www.quintillion.com/moat/wish.list
- use of random numbers needs to be audited.
- unknown (not just unimplemented) transforms cause a negotiation to
fail. Only the transform should be rejected.
- we need better policy control. Our present flags need to be
modulated (forbid, allow, offer, require)
- HS will specify how --copyright and --version should behave
- HS will initiate project-wide terminology replacing ISAKMP SA, IPSEC
SA, Protection Suite, Phase 1, Main Mode, Phase 2, Quick Mode, ...
Simplicity and clarity will be a goal.
- interface discovery ought to match what is specified in ipsec.conf.
This probably means grokking /proc/net/ipsec_tncfg. Documented in
ipsec_tncfg(5). This won't do for Hugh's debugging setup.
Protocol Issues
===============
Notification and delete payloads seem to be "escape hatches" for the
protocols. As such, anything implemented using them seems to be
kludged without being well designed or well situated or well
constrained in the protocols. Often the precise meaning (if any) or
usage is under specified. An implementation is allowed to ignore
them, so they cannot really matter (but they too often do). Their
specification ought to be scrutinized by a protocol guru.
Any extra payload in last main mode message is not protected (not
authenticated by hash).
Should notification payloads be interpreted before or after the normal
payloads (i.e. understood in the context of, executed in the context of).
What is the precise result of an INITIAL_CONNECTION? What is a
"system" (eg. does Phase 1 Identity count)? What is "earlier" or
"before" (simultaneous negotiation is possible, with time being only a
partial order)? Could it be used for FINAL_CONTACT (needed too)?
Blasting out a pile of UDP messages, especially to a particular
destination, is likely to provoke message loss. The exchanges are
just that, so they individually are self-throttling. But what about
multiple exchanges simultaneously? What about notifications (example:
when shutting down, a flurry of delete notifications are likely).
Should the RFCs be designed to protect against this problem?
draft-jenkins-ipsec-rekeying-03.txt rekeying is way too complicated.
Our solution looks sound and simple (we have the Responder install the
incoming IPSEC SA before sending its first reply). In "2.2.1.4
Responder Pre-Set-up Security Hole", the draft claims that setting up
the IPSEC SA early leaves the Responder open to replay attacks. I
think that this is wrong: the Message Id, since it must not be reused,
serves to prove that this isn't a replay.
The details for notification messages suggested by
draft-ietf-ipsec-notifymsg-02.txt are over-complicated, just to make
them machine-comprehensible. I think this is over-engineering,
justified only if another level of negotiation is contemplated (ugh!).
Plain text is probably sufficient for informing humans (I admit that
there is a problem with I18N).
+1018
View File
File diff suppressed because it is too large Load Diff
+103
View File
@@ -0,0 +1,103 @@
/* Support of X.509 attribute certificates
* Copyright (C) 2002 Ueli Galizzi, Ariane Seiler
* Copyright (C) 2003 Martin Berner, Lukas Suter
*
* 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: ac.h,v 1.8 2005/02/17 20:56:04 as Exp $
*/
#ifndef _AC_H
#define _AC_H
/* definition of ietfAttribute kinds */
typedef enum {
IETF_ATTRIBUTE_OCTETS = 0,
IETF_ATTRIBUTE_OID = 1,
IETF_ATTRIBUTE_STRING = 2
} ietfAttribute_t;
/* access structure for an ietfAttribute */
typedef struct ietfAttr ietfAttr_t;
struct ietfAttr {
time_t installed;
int count;
ietfAttribute_t kind;
chunk_t value;
};
typedef struct ietfAttrList ietfAttrList_t;
struct ietfAttrList {
ietfAttrList_t *next;
ietfAttr_t *attr;
};
/* access structure for an X.509 attribute certificate */
typedef struct x509acert x509acert_t;
struct x509acert {
x509acert_t *next;
time_t installed;
chunk_t certificate;
chunk_t certificateInfo;
u_int version;
/* holder */
/* baseCertificateID */
chunk_t holderIssuer;
chunk_t holderSerial;
chunk_t entityName;
/* v2Form */
chunk_t issuerName;
/* signature */
int sigAlg;
chunk_t serialNumber;
/* attrCertValidityPeriod */
time_t notBefore;
time_t notAfter;
/* attributes */
ietfAttrList_t *charging;
ietfAttrList_t *groups;
/* extensions */
chunk_t authKeyID;
chunk_t authKeySerialNumber;
bool noRevAvail;
/* signatureAlgorithm */
int algorithm;
chunk_t signature;
};
/* used for initialization */
extern const x509acert_t empty_ac;
extern void unshare_ietfAttrList(ietfAttrList_t **listp);
extern void free_ietfAttrList(ietfAttrList_t *list);
extern void decode_groups(char *groups, ietfAttrList_t **listp);
extern bool group_membership(const ietfAttrList_t *my_list
, const char *conn, const ietfAttrList_t *conn_list);
extern bool parse_ac(chunk_t blob, x509acert_t *ac);
extern bool verify_x509acert(x509acert_t *ac, bool strict);
extern x509acert_t* get_x509acert(chunk_t issuer, chunk_t serial);
extern void load_acerts(void);
extern void free_acert(x509acert_t *ac);
extern void free_acerts(void);
extern void list_acerts(bool utc);
extern void list_groups(bool utc);
extern void format_groups(const ietfAttrList_t *list, char *buf, int len);
#endif /* _AH_H */
+615
View File
@@ -0,0 +1,615 @@
/* Pluto Asynchronous DNS Helper Program -- for internal use only!
* Copyright (C) 2002 D. Hugh Redelmeier.
*
* 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: adns.c,v 1.1 2004/03/15 20:35:28 as Exp $
*/
#ifndef USE_LWRES /* whole file! */
/* This program executes as multiple processes. The Master process
* receives queries (struct adns_query messages) from Pluto and distributes
* them amongst Worker processes. These Worker processes are created
* by the Master whenever a query arrives and no existing Worker is free.
* At most MAX_WORKERS will be created; after that, the Master will queue
* queries until a Worker becomes free. When a Worker has an answer from
* the resolver, it sends the answer as a struct adns_answer message to the
* Master. The Master then forwards the answer to Pluto, noting that
* the Worker is free to accept another query.
*
* The protocol is simple: Pluto sends a sequence of queries and receives
* a sequence of answers. select(2) is used by Pluto and by the Master
* process to decide when to read, but writes are done without checking
* for readiness. Communications is via pipes. Since only one process
* can write to each pipe, messages will not be interleaved. Fixed length
* records are used for simplicity.
*
* Pluto needs a way to indicate to the Master when to shut down
* and the Master needs to indicate this to each worker. EOF on the pipe
* signifies this.
*
* The interfaces between these components are considered private to
* Pluto. This allows us to get away with less checking. This is a
* reason to use pipes instead of TCP/IP.
*
* Although the code uses plain old UNIX processes, it could be modified
* to use threads. That might reduce resource requirements. It would
* preclude running on systems without thread-safe resolvers.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <netdb.h> /* ??? for h_errno */
#include <freeswan.h>
/* GCC magic! */
#ifdef GCC_LINT
# define UNUSED __attribute__ ((unused))
#else
# define UNUSED /* ignore */
#endif
#include "constants.h"
#include "adns.h" /* needs <resolv.h> */
/* shared by all processes */
static const char *name; /* program name, for messages */
static bool debug = FALSE;
/* Read a variable-length record from a pipe (and no more!).
* First bytes must be a size_t containing the length.
* HES_CONTINUE if record read
* HES_OK if EOF
* HES_IO_ERROR_IN if errno tells the tale.
* Others are errors.
*/
static enum helper_exit_status
read_pipe(int fd, unsigned char *stuff, size_t minlen, size_t maxlen)
{
size_t n = 0;
size_t goal = minlen;
do {
ssize_t m = read(fd, stuff + n, goal - n);
if (m == -1)
{
if (errno != EINTR)
{
syslog(LOG_ERR, "Input error on pipe: %s", strerror(errno));
return HES_IO_ERROR_IN;
}
}
else if (m == 0)
{
return HES_OK; /* treat empty message as EOF */
}
else
{
n += m;
if (n >= sizeof(size_t))
{
goal = *(size_t *)(void *)stuff;
if (goal < minlen || maxlen < goal)
{
if (debug)
fprintf(stderr, "%lu : [%lu, %lu]\n"
, (unsigned long)goal
, (unsigned long)minlen, (unsigned long)maxlen);
return HES_BAD_LEN;
}
}
}
} while (n < goal);
return HES_CONTINUE;
}
/* Write a variable-length record to a pipe.
* First bytes must be a size_t containing the length.
* HES_CONTINUE if record written
* Others are errors.
*/
static enum helper_exit_status
write_pipe(int fd, const unsigned char *stuff)
{
size_t len = *(const size_t *)(const void *)stuff;
size_t n = 0;
do {
ssize_t m = write(fd, stuff + n, len - n);
if (m == -1)
{
/* error, but ignore and retry if EINTR */
if (errno != EINTR)
{
syslog(LOG_ERR, "Output error from master: %s", strerror(errno));
return HES_IO_ERROR_OUT;
}
}
else
{
n += m;
}
} while (n != len);
return HES_CONTINUE;
}
/**************** worker process ****************/
/* The interface in RHL6.x and BIND distribution 8.2.2 are different,
* so we build some of our own :-(
*/
/* Support deprecated interface to allow for older releases of the resolver.
* Fake new interface!
* See resolver(3) bind distribution (should be in RHL6.1, but isn't).
* __RES was 19960801 in RHL6.2, an old resolver.
*/
#if (__RES) <= 19960801
# define OLD_RESOLVER 1
#endif
#ifdef OLD_RESOLVER
# define res_ninit(statp) res_init()
# define res_nquery(statp, dname, class, type, answer, anslen) \
res_query(dname, class, type, answer, anslen)
# define res_nclose(statp) res_close()
static struct __res_state *statp = &_res;
#else /* !OLD_RESOLVER */
static struct __res_state my_res_state /* = { 0 } */;
static res_state statp = &my_res_state;
#endif /* !OLD_RESOLVER */
static int
worker(int qfd, int afd)
{
{
int r = res_ninit(statp);
if (r != 0)
{
syslog(LOG_ERR, "cannot initialize resolver");
return HES_RES_INIT;
}
#ifndef OLD_RESOLVER
statp->options |= RES_ROTATE;
#endif
statp->options |= RES_DEBUG;
}
for (;;)
{
struct adns_query q;
struct adns_answer a;
enum helper_exit_status r = read_pipe(qfd, (unsigned char *)&q
, sizeof(q), sizeof(q));
if (r != HES_CONTINUE)
return r; /* some kind of exit */
if (q.qmagic != ADNS_Q_MAGIC)
{
syslog(LOG_ERR, "error in input from master: bad magic");
return HES_BAD_MAGIC;
}
a.amagic = ADNS_A_MAGIC;
a.serial = q.serial;
a.result = res_nquery(statp, q.name_buf, C_IN, q.type, a.ans, sizeof(a.ans));
a.h_errno_val = h_errno;
a.len = offsetof(struct adns_answer, ans) + (a.result < 0? 0 : a.result);
#ifdef DEBUG
if (((q.debugging & IMPAIR_DELAY_ADNS_KEY_ANSWER) && q.type == T_KEY)
|| ((q.debugging & IMPAIR_DELAY_ADNS_TXT_ANSWER) && q.type == T_TXT))
sleep(30); /* delay the answer */
#endif
/* write answer, possibly a bit at a time */
r = write_pipe(afd, (const unsigned char *)&a);
if (r != HES_CONTINUE)
return r; /* some kind of exit */
}
}
/**************** master process ****************/
bool eof_from_pluto = FALSE;
#define PLUTO_QFD 0 /* queries come on stdin */
#define PLUTO_AFD 1 /* answers go out on stdout */
#ifndef MAX_WORKERS
# define MAX_WORKERS 10 /* number of in-flight queries */
#endif
struct worker_info {
int qfd; /* query pipe's file descriptor */
int afd; /* answer pipe's file descriptor */
pid_t pid;
bool busy;
void *continuation; /* of outstanding request */
};
static struct worker_info wi[MAX_WORKERS];
static struct worker_info *wi_roof = wi;
/* request FIFO */
struct query_list {
struct query_list *next;
struct adns_query aq;
};
static struct query_list *oldest_query = NULL;
static struct query_list *newest_query; /* undefined when oldest == NULL */
static struct query_list *free_queries = NULL;
static bool
spawn_worker(void)
{
int qfds[2];
int afds[2];
pid_t p;
if (pipe(qfds) != 0 || pipe(afds) != 0)
{
syslog(LOG_ERR, "pipe(2) failed: %s", strerror(errno));
exit(HES_PIPE);
}
wi_roof->qfd = qfds[1]; /* write end of query pipe */
wi_roof->afd = afds[0]; /* read end of answer pipe */
p = fork();
if (p == -1)
{
/* fork failed: ignore if at least one worker exists */
if (wi_roof == wi)
{
syslog(LOG_ERR, "fork(2) error creating first worker: %s", strerror(errno));
exit(HES_FORK);
}
close(qfds[0]);
close(qfds[1]);
close(afds[0]);
close(afds[1]);
return FALSE;
}
else if (p == 0)
{
/* child */
struct worker_info *w;
close(PLUTO_QFD);
close(PLUTO_AFD);
/* close all master pipes, including ours */
for (w = wi; w <= wi_roof; w++)
{
close(w->qfd);
close(w->afd);
}
exit(worker(qfds[0], afds[1]));
}
else
{
/* parent */
struct worker_info *w = wi_roof++;
w->pid = p;
w->busy = FALSE;
close(qfds[0]);
close(afds[1]);
return TRUE;
}
}
static void
send_eof(struct worker_info *w)
{
pid_t p;
int status;
close(w->qfd);
w->qfd = NULL_FD;
close(w->afd);
w->afd = NULL_FD;
/* reap child */
p = waitpid(w->pid, &status, 0);
/* ignore result -- what could we do with it? */
}
static void
forward_query(struct worker_info *w)
{
struct query_list *q = oldest_query;
if (q == NULL)
{
if (eof_from_pluto)
send_eof(w);
}
else
{
enum helper_exit_status r
= write_pipe(w->qfd, (const unsigned char *) &q->aq);
if (r != HES_CONTINUE)
exit(r);
w->busy = TRUE;
oldest_query = q->next;
q->next = free_queries;
free_queries = q;
}
}
static void
query(void)
{
struct query_list *q = free_queries;
enum helper_exit_status r;
/* find an unused queue entry */
if (q == NULL)
{
q = malloc(sizeof(*q));
if (q == NULL)
{
syslog(LOG_ERR, "malloc(3) failed");
exit(HES_MALLOC);
}
}
else
{
free_queries = q->next;
}
r = read_pipe(PLUTO_QFD, (unsigned char *)&q->aq
, sizeof(q->aq), sizeof(q->aq));
if (r == HES_OK)
{
/* EOF: we're done, except for unanswered queries */
struct worker_info *w;
eof_from_pluto = TRUE;
q->next = free_queries;
free_queries = q;
/* Send bye-bye to unbusy processes.
* Note that if there are queued queries, there won't be
* any non-busy workers.
*/
for (w = wi; w != wi_roof; w++)
if (!w->busy)
send_eof(w);
}
else if (r != HES_CONTINUE)
{
exit(r);
}
else if (q->aq.qmagic != ADNS_Q_MAGIC)
{
syslog(LOG_ERR, "error in query from Pluto: bad magic");
exit(HES_BAD_MAGIC);
}
else
{
struct worker_info *w;
/* got a query */
/* add it to FIFO */
q->next = NULL;
if (oldest_query == NULL)
oldest_query = q;
else
newest_query->next = q;
newest_query = q;
/* See if any worker available */
for (w = wi; ; w++)
{
if (w == wi_roof)
{
/* no free worker */
if (w == wi + MAX_WORKERS)
break; /* no more to be created */
/* make a new one */
if (!spawn_worker())
break; /* cannot create one at this time */
}
if (!w->busy)
{
/* assign first to free worker */
forward_query(w);
break;
}
}
}
return;
}
static void
answer(struct worker_info *w)
{
struct adns_answer a;
enum helper_exit_status r = read_pipe(w->afd, (unsigned char *)&a
, offsetof(struct adns_answer, ans), sizeof(a));
if (r == HES_OK)
{
/* unexpected EOF */
syslog(LOG_ERR, "unexpected EOF from worker");
exit(HES_IO_ERROR_IN);
}
else if (r != HES_CONTINUE)
{
exit(r);
}
else if (a.amagic != ADNS_A_MAGIC)
{
syslog(LOG_ERR, "Input from worker error: bad magic");
exit(HES_BAD_MAGIC);
}
else if (a.continuation != w->continuation)
{
/* answer doesn't match query */
syslog(LOG_ERR, "Input from worker error: continuation mismatch");
exit(HES_SYNC);
}
else
{
/* pass the answer on to Pluto */
enum helper_exit_status r
= write_pipe(PLUTO_AFD, (const unsigned char *) &a);
if (r != HES_CONTINUE)
exit(r);
w->busy = FALSE;
forward_query(w);
}
}
/* assumption: input limited; accept blocking on output */
static int
master(void)
{
for (;;)
{
fd_set readfds;
int maxfd = PLUTO_QFD; /* approximate lower bound */
int ndes = 0;
struct worker_info *w;
FD_ZERO(&readfds);
if (!eof_from_pluto)
{
FD_SET(PLUTO_QFD, &readfds);
ndes++;
}
for (w = wi; w != wi_roof; w++)
{
if (w->busy)
{
FD_SET(w->afd, &readfds);
ndes++;
if (maxfd < w->afd)
maxfd = w->afd;
}
}
if (ndes == 0)
return HES_OK; /* done! */
do {
ndes = select(maxfd + 1, &readfds, NULL, NULL, NULL);
} while (ndes == -1 && errno == EINTR);
if (ndes == -1)
{
syslog(LOG_ERR, "select(2) error: %s", strerror(errno));
exit(HES_IO_ERROR_SELECT);
}
else if (ndes > 0)
{
if (FD_ISSET(PLUTO_QFD, &readfds))
{
query();
ndes--;
}
for (w = wi; ndes > 0 && w != wi_roof; w++)
{
if (w->busy && FD_ISSET(w->afd, &readfds))
{
answer(w);
ndes--;
}
}
}
}
}
/* Not to be invoked by strangers -- user hostile.
* Mandatory args: query-fd answer-fd
* Optional arg: -d, signifying "debug".
*/
static void
adns_usage(const char *fmt, const char *arg)
{
const char **sp = ipsec_copyright_notice();
fprintf(stderr, "INTERNAL TO PLUTO: DO NOT EXECUTE\n");
fprintf(stderr, fmt, arg);
fprintf(stderr, "\n%s\n", ipsec_version_string());
for (; *sp != NULL; sp++)
fprintf(stderr, "%s\n", *sp);
syslog(LOG_ERR, fmt, arg);
exit(HES_INVOCATION);
}
int
main(int argc UNUSED, char **argv)
{
int i = 1;
name = argv[0];
while (i < argc)
{
if (streq(argv[i], "-d"))
{
i++;
debug = TRUE;
}
else
{
adns_usage("unexpected argument \"%s\"", argv[i]);
/*NOTREACHED*/
}
}
return master();
}
#endif /* !USE_LWRES */
+75
View File
@@ -0,0 +1,75 @@
/* Pluto Asynchronous DNS Helper Program's Header
* Copyright (C) 2002 D. Hugh Redelmeier.
*
* 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: adns.h,v 1.1 2004/03/15 20:35:28 as Exp $
*/
#ifndef USE_LWRES /* whole file! */
/* The interface in RHL6.x and BIND distribution 8.2.2 are different,
* so we build some of our own :-(
*/
# ifndef NS_MAXDNAME
# define NS_MAXDNAME MAXDNAME /* I hope this is long enough for IPv6 */
# endif
# ifndef NS_PACKETSZ
# define NS_PACKETSZ PACKETSZ
# endif
/* protocol version */
#define ADNS_Q_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 4)
#define ADNS_A_MAGIC (((((('d' << 8) + 'n') << 8) + 's') << 8) + 128 + 4)
/* note: both struct adns_query and struct adns_answer must start with
* size_t len;
*/
struct adns_query {
size_t len;
unsigned int qmagic;
unsigned long serial;
lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */
u_char name_buf[NS_MAXDNAME + 2];
int type; /* T_KEY or T_TXT */
};
struct adns_answer {
size_t len;
unsigned int amagic;
unsigned long serial;
struct adns_continuation *continuation;
int result;
int h_errno_val;
u_char ans[NS_PACKETSZ * 10]; /* very probably bigger than necessary */
};
enum helper_exit_status {
HES_CONTINUE = -1, /* not an exit */
HES_OK = 0, /* all's well that ends well (perhaps EOF) */
HES_INVOCATION, /* improper invocation */
HES_IO_ERROR_SELECT, /* IO error in select() */
HES_MALLOC, /* malloc failed */
HES_IO_ERROR_IN, /* error reading pipe */
HES_IO_ERROR_OUT, /* error reading pipe */
HES_PIPE, /* pipe(2) failed */
HES_SYNC, /* answer from worker doesn't match query */
HES_FORK, /* fork(2) failed */
HES_RES_INIT, /* resolver initialization failed */
HES_BAD_LEN, /* implausible .len field */
HES_BAD_MAGIC, /* .magic field wrong */
};
#endif /* !USE_LWRES */
+9
View File
@@ -0,0 +1,9 @@
##
## IKE algorithms config. for static linking into pluto
## By now 3DES,MD5 and SHA1 are already present in pluto.
##
CONFIG_IKE_ALG_AES=y
CONFIG_IKE_ALG_BLOWFISH=y
CONFIG_IKE_ALG_SERPENT=y
CONFIG_IKE_ALG_TWOFISH=y
CONFIG_IKE_ALG_SHA2=y
+93
View File
@@ -0,0 +1,93 @@
# pluto/alg Makefile
# Author: JuanJo Ciarlante <[email protected]>
#
# 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.
#
# $Id: Makefile,v 1.3 2004/06/23 04:45:20 as Exp $
Make.common: ../Makefile
make -s -C .. showdefs > $@
-include Make.common
include Config.ike_alg
LIBCRYPTO:=../../../lib/libcrypto
ALLFLAGS=$(CPPFLAGS) $(CFLAGS) -I .. -I- -I ../../../linux/include -I $(LIBCRYPTO)
LIBALG := libalg.o
all : $(LIBALG)
include $(wildcard Makefile.ike_alg_*)
#include $(wildcard Makefile.ike_alg_[ab]*)
ALG_DIRS:=$(ALG_DIRS-y)
ALG_LIBS:=$(ALG_LIBS-y)
ALG_SRCS:=$(ALG_SRCS-y)
ALG_OBJS:=$(ALG_OBJS-y)
$(LIBALG): ike_alginit.o $(ALG_OBJS) $(ALG_LIBS)
$(LD) -r -o $@ $^
# Search for IKE_ALG_INIT_NAME: in ike_alg_*.c to
# build ike_alginit.c:ike_alginit()
ike_alginit.c: $(ALG_SRCS) Makefile Config.ike_alg
@awk ' \
BEGIN { print "extern int ike_alg_init(void); \
int ike_alg_init(void) {" } \
/IKE_ALG_INIT_NAME:/ \
{ print "{ extern int " $$2" (void); " $$2 "();}" } \
END { print "return 0;}" } \
' $(ALG_SRCS) /dev/null > $@
clean :
@for i in $(ALG_DIRS);do make -C $$i clean;done
rm -f *.[oa] ike_alginit.c Make.common
gatherdeps:
@ls $(ALG_SRCS) | grep '\.c' | sed -e 's/\(.*\)\.c$$/\1.o: \1.c/'
@echo
@ls $(ALG_SRCS) | grep '\.c' | xargs grep '^#[ ]*include[ ]*"' | \
sed -n -e '/#include.*"lib/d' \
-e 's/\.c:#[ ]*include[ ]*"/.o: ..\//' -e 's/".*//p'
# Dependencies generated by "make gatherdeps":
ike_alg_aes.o: ike_alg_aes.c
ike_alg_blowfish.o: ike_alg_blowfish.c
ike_alg_serpent.o: ike_alg_serpent.c
ike_alg_sha2.o: ike_alg_sha2.c
ike_alg_twofish.o: ike_alg_twofish.c
ike_alg_aes.o: ../constants.h
ike_alg_aes.o: ../defs.h
ike_alg_aes.o: ../log.h
ike_alg_aes.o: ../alg_info.h
ike_alg_aes.o: ../ike_alg.h
ike_alg_blowfish.o: ../constants.h
ike_alg_blowfish.o: ../defs.h
ike_alg_blowfish.o: ../log.h
ike_alg_blowfish.o: ../alg_info.h
ike_alg_blowfish.o: ../ike_alg.h
ike_alg_serpent.o: ../constants.h
ike_alg_serpent.o: ../defs.h
ike_alg_serpent.o: ../log.h
ike_alg_serpent.o: ../alg_info.h
ike_alg_serpent.o: ../ike_alg.h
ike_alg_sha2.o: ../constants.h
ike_alg_sha2.o: ../defs.h
ike_alg_sha2.o: ../log.h
ike_alg_sha2.o: ../alg_info.h
ike_alg_sha2.o: ../ike_alg.h
ike_alg_twofish.o: ../constants.h
ike_alg_twofish.o: ../defs.h
ike_alg_twofish.o: ../log.h
ike_alg_twofish.o: ../alg_info.h
ike_alg_twofish.o: ../ike_alg.h
+14
View File
@@ -0,0 +1,14 @@
ALG:=aes
CONFIG_YES:=$(CONFIG_IKE_ALG_AES)
DIR_AES:=$(LIBCRYPTO)/libaes
ALG_DIRS-$(CONFIG_YES) := $(ALG_DIRS-$(CONFIG_YES)) $(DIR_AES)
ALG_LIBS-$(CONFIG_YES) := $(ALG_LIBS-$(CONFIG_YES)) $(DIR_AES)/libaes.a
ALG_SRCS-$(CONFIG_YES) := $(ALG_SRCS-$(CONFIG_YES)) ike_alg_$(ALG).c
ALG_OBJS-$(CONFIG_YES) := $(ALG_OBJS-$(CONFIG_YES)) ike_alg_$(ALG).o
$(DIR_AES)/libaes.a:
make -C $(DIR_AES) CFLAGS="$(CFLAGS)" libaes.a
ike_alg_$(ALG).o: ike_alg_$(ALG).c
$(CC) -I $(LIBCRYPTO) -I$(DIR_AES) $(COPTS) $(ALLFLAGS) -c $<
+13
View File
@@ -0,0 +1,13 @@
ALG:=blowfish
CONFIG_YES:=$(CONFIG_IKE_ALG_BLOWFISH)
DIR_BLOWFISH:=$(LIBCRYPTO)/libblowfish
ALG_DIRS-$(CONFIG_YES) := $(ALG_DIRS-$(CONFIG_YES)) $(DIR_BLOWFISH)
ALG_LIBS-$(CONFIG_YES) := $(ALG_LIBS-$(CONFIG_YES)) $(DIR_BLOWFISH)/libblowfish.a
ALG_SRCS-$(CONFIG_YES) := $(ALG_SRCS-$(CONFIG_YES)) ike_alg_$(ALG).c
ALG_OBJS-$(CONFIG_YES) := $(ALG_OBJS-$(CONFIG_YES)) ike_alg_$(ALG).o
$(DIR_BLOWFISH)/libblowfish.a:
make -C $(DIR_BLOWFISH) CFLAGS="$(CFLAGS)" libblowfish.a
ike_alg_$(ALG).o: ike_alg_$(ALG).c
$(CC) -I $(LIBCRYPTO) -I$(DIR_BLOWFISH) $(COPTS) $(ALLFLAGS) -c $<
+13
View File
@@ -0,0 +1,13 @@
ALG:=serpent
CONFIG_YES:=$(CONFIG_IKE_ALG_SERPENT)
DIR_SERPENT:=$(LIBCRYPTO)/libserpent
ALG_DIRS-$(CONFIG_YES) := $(ALG_DIRS-$(CONFIG_YES)) $(DIR_SERPENT)
ALG_LIBS-$(CONFIG_YES) := $(ALG_LIBS-$(CONFIG_YES)) $(DIR_SERPENT)/libserpent.a
ALG_SRCS-$(CONFIG_YES) := $(ALG_SRCS-$(CONFIG_YES)) ike_alg_$(ALG).c
ALG_OBJS-$(CONFIG_YES) := $(ALG_OBJS-$(CONFIG_YES)) ike_alg_$(ALG).o
$(DIR_SERPENT)/libserpent.a:
make -C $(DIR_SERPENT) CFLAGS="$(CFLAGS)" libserpent.a
ike_alg_$(ALG).o: ike_alg_$(ALG).c
$(CC) -I $(LIBCRYPTO) -I$(DIR_SERPENT) $(COPTS) $(ALLFLAGS) -c $<
+13
View File
@@ -0,0 +1,13 @@
ALG:=sha2
CONFIG_YES:=$(CONFIG_IKE_ALG_SHA2)
DIR_SHA2:=$(LIBCRYPTO)/libsha2
ALG_DIRS-$(CONFIG_YES) := $(ALG_DIRS-$(CONFIG_YES)) $(DIR_SHA2)
ALG_LIBS-$(CONFIG_YES) := $(ALG_LIBS-$(CONFIG_YES)) $(DIR_SHA2)/libsha2.a
ALG_SRCS-$(CONFIG_YES) := $(ALG_SRCS-$(CONFIG_YES)) ike_alg_$(ALG).c
ALG_OBJS-$(CONFIG_YES) := $(ALG_OBJS-$(CONFIG_YES)) ike_alg_$(ALG).o
$(DIR_SHA2)/libsha2.a:
make -C $(DIR_SHA2) libsha2.a
ike_alg_$(ALG).o: ike_alg_$(ALG).c
$(CC) -I $(LIBCRYPTO) -I$(DIR_SHA2) $(COPTS) $(ALLFLAGS) -c $<
+13
View File
@@ -0,0 +1,13 @@
ALG:=twofish
CONFIG_YES:=$(CONFIG_IKE_ALG_TWOFISH)
DIR_TWOFISH:=$(LIBCRYPTO)/libtwofish
ALG_DIRS-$(CONFIG_YES) := $(ALG_DIRS-$(CONFIG_YES)) $(DIR_TWOFISH)
ALG_LIBS-$(CONFIG_YES) := $(ALG_LIBS-$(CONFIG_YES)) $(DIR_TWOFISH)/libtwofish.a
ALG_SRCS-$(CONFIG_YES) := $(ALG_SRCS-$(CONFIG_YES)) ike_alg_$(ALG).c
ALG_OBJS-$(CONFIG_YES) := $(ALG_OBJS-$(CONFIG_YES)) ike_alg_$(ALG).o
$(DIR_TWOFISH)/libtwofish.a:
make -C $(DIR_TWOFISH) CFLAGS="$(CFLAGS)" libtwofish.a
ike_alg_$(ALG).o: ike_alg_$(ALG).c
$(CC) -I $(LIBCRYPTO) -I$(DIR_TWOFISH) $(COPTS) $(ALLFLAGS) -c $<
+68
View File
@@ -0,0 +1,68 @@
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <sys/types.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "libaes/aes_cbc.h"
#include "alg_info.h"
#include "ike_alg.h"
#define AES_CBC_BLOCK_SIZE (128/BITS_PER_BYTE)
#define AES_KEY_MIN_LEN 128
#define AES_KEY_DEF_LEN 128
#define AES_KEY_MAX_LEN 256
static void
do_aes(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
{
aes_context aes_ctx;
char iv_bak[AES_CBC_BLOCK_SIZE];
char *new_iv = NULL; /* logic will avoid copy to NULL */
aes_set_key(&aes_ctx, key, key_size, 0);
/*
* my AES cbc does not touch passed IV (optimization for
* ESP handling), so I must "emulate" des-like IV
* crunching
*/
if (!enc)
memcpy(new_iv=iv_bak, (char*) buf + buf_len - AES_CBC_BLOCK_SIZE
, AES_CBC_BLOCK_SIZE);
AES_cbc_encrypt(&aes_ctx, buf, buf, buf_len, iv, enc);
if (enc)
new_iv = (char*) buf + buf_len-AES_CBC_BLOCK_SIZE;
memcpy(iv, new_iv, AES_CBC_BLOCK_SIZE);
}
struct encrypt_desc algo_aes =
{
algo_type: IKE_ALG_ENCRYPT,
algo_id: OAKLEY_AES_CBC,
algo_next: NULL,
enc_ctxsize: sizeof(aes_context),
enc_blocksize: AES_CBC_BLOCK_SIZE,
keyminlen: AES_KEY_MIN_LEN,
keydeflen: AES_KEY_DEF_LEN,
keymaxlen: AES_KEY_MAX_LEN,
do_crypt: do_aes,
};
int ike_alg_aes_init(void);
int
ike_alg_aes_init(void)
{
int ret = ike_alg_register_enc(&algo_aes);
return ret;
}
/*
IKE_ALG_INIT_NAME: ike_alg_aes_init
*/
+52
View File
@@ -0,0 +1,52 @@
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <sys/types.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "libblowfish/blowfish.h"
#include "alg_info.h"
#include "ike_alg.h"
#define BLOWFISH_CBC_BLOCK_SIZE 8 /* block size */
#define BLOWFISH_KEY_MIN_LEN 128
#define BLOWFISH_KEY_MAX_LEN 448
static void
do_blowfish(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
{
BF_KEY bf_ctx;
BF_set_key(&bf_ctx, key_size , key);
BF_cbc_encrypt(buf, buf, buf_len, &bf_ctx, iv, enc);
}
struct encrypt_desc algo_blowfish =
{
algo_type: IKE_ALG_ENCRYPT,
algo_id: OAKLEY_BLOWFISH_CBC,
algo_next: NULL,
enc_ctxsize: sizeof(BF_KEY),
enc_blocksize: BLOWFISH_CBC_BLOCK_SIZE,
keyminlen: BLOWFISH_KEY_MIN_LEN,
keydeflen: BLOWFISH_KEY_MIN_LEN,
keymaxlen: BLOWFISH_KEY_MAX_LEN,
do_crypt: do_blowfish,
};
int ike_alg_blowfish_init(void);
int
ike_alg_blowfish_init(void)
{
int ret = ike_alg_register_enc(&algo_blowfish);
return ret;
}
/*
IKE_ALG_INIT_NAME: ike_alg_blowfish_init
*/
+70
View File
@@ -0,0 +1,70 @@
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <sys/types.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "libserpent/serpent_cbc.h"
#include "alg_info.h"
#include "ike_alg.h"
#define SERPENT_CBC_BLOCK_SIZE (128/BITS_PER_BYTE)
#define SERPENT_KEY_MIN_LEN 128
#define SERPENT_KEY_DEF_LEN 128
#define SERPENT_KEY_MAX_LEN 256
static void
do_serpent(u_int8_t *buf, size_t buf_size, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
{
serpent_context serpent_ctx;
char iv_bak[SERPENT_CBC_BLOCK_SIZE];
char *new_iv = NULL; /* logic will avoid copy to NULL */
serpent_set_key(&serpent_ctx, key, key_size);
/*
* my SERPENT cbc does not touch passed IV (optimization for
* ESP handling), so I must "emulate" des-like IV
* crunching
*/
if (!enc)
memcpy(new_iv=iv_bak,
(char*) buf + buf_size-SERPENT_CBC_BLOCK_SIZE,
SERPENT_CBC_BLOCK_SIZE);
serpent_cbc_encrypt(&serpent_ctx, buf, buf, buf_size, iv, enc);
if (enc)
new_iv = (char*) buf + buf_size-SERPENT_CBC_BLOCK_SIZE;
memcpy(iv, new_iv, SERPENT_CBC_BLOCK_SIZE);
}
struct encrypt_desc encrypt_desc_serpent =
{
algo_type: IKE_ALG_ENCRYPT,
algo_id: OAKLEY_SERPENT_CBC,
algo_next: NULL,
enc_ctxsize: sizeof(struct serpent_context),
enc_blocksize: SERPENT_CBC_BLOCK_SIZE,
keyminlen: SERPENT_KEY_MIN_LEN,
keydeflen: SERPENT_KEY_DEF_LEN,
keymaxlen: SERPENT_KEY_MAX_LEN,
do_crypt: do_serpent,
};
int ike_alg_serpent_init(void);
int
ike_alg_serpent_init(void)
{
int ret = ike_alg_register_enc(&encrypt_desc_serpent);
return ret;
}
/*
IKE_ALG_INIT_NAME: ike_alg_serpent_init
*/
+61
View File
@@ -0,0 +1,61 @@
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <sys/types.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "libsha2/sha2.h"
#include "alg_info.h"
#include "ike_alg.h"
#define SHA2_256_DIGEST_SIZE (256/BITS_PER_BYTE)
#define SHA2_512_DIGEST_SIZE (512/BITS_PER_BYTE)
static void sha256_hash_final(u_char *hash, sha256_context *ctx)
{
sha256_final(ctx);
memcpy(hash, &ctx->sha_out[0], SHA2_256_DIGEST_SIZE);
}
static void sha512_hash_final(u_char *hash, sha512_context *ctx)
{
sha512_final(ctx);
memcpy(hash, &ctx->sha_out[0], SHA2_512_DIGEST_SIZE);
}
struct hash_desc hash_desc_sha2_256 = {
algo_type: IKE_ALG_HASH,
algo_id: OAKLEY_SHA2_256,
algo_next: NULL,
hash_ctx_size: sizeof(sha256_context),
hash_init: (void (*)(void *))sha256_init,
hash_update: (void (*)(void *, const u_char *, size_t ))sha256_write,
hash_final:(void (*)(u_char *, void *))sha256_hash_final,
hash_digest_size: SHA2_256_DIGEST_SIZE,
};
struct hash_desc hash_desc_sha2_512 = {
algo_type: IKE_ALG_HASH,
algo_id: OAKLEY_SHA2_512,
algo_next: NULL,
hash_ctx_size: sizeof(sha512_context),
hash_init: (void (*)(void *))sha512_init,
hash_update: (void (*)(void *, const u_char *, size_t ))sha512_write,
hash_final:(void (*)(u_char *, void *))sha512_hash_final,
hash_digest_size: SHA2_512_DIGEST_SIZE,
};
int ike_alg_sha2_init(void);
int
ike_alg_sha2_init(void)
{
int ret;
ret = ike_alg_register_hash(&hash_desc_sha2_256);
if (ret)
goto out;
ret = ike_alg_register_hash(&hash_desc_sha2_512);
out:
return ret;
}
/*
IKE_ALG_INIT_NAME: ike_alg_sha2_init
*/
+85
View File
@@ -0,0 +1,85 @@
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <sys/types.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "libtwofish/twofish_cbc.h"
#include "alg_info.h"
#include "ike_alg.h"
#define TWOFISH_CBC_BLOCK_SIZE (128/BITS_PER_BYTE)
#define TWOFISH_KEY_MIN_LEN 128
#define TWOFISH_KEY_DEF_LEN 128
#define TWOFISH_KEY_MAX_LEN 256
static void
do_twofish(u_int8_t *buf, size_t buf_size, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
{
twofish_context twofish_ctx;
char iv_bak[TWOFISH_CBC_BLOCK_SIZE];
char *new_iv = NULL; /* logic will avoid copy to NULL */
twofish_set_key(&twofish_ctx, key, key_size);
/*
* my TWOFISH cbc does not touch passed IV (optimization for
* ESP handling), so I must "emulate" des-like IV
* crunching
*/
if (!enc)
memcpy(new_iv=iv_bak,
(char*) buf + buf_size-TWOFISH_CBC_BLOCK_SIZE,
TWOFISH_CBC_BLOCK_SIZE);
twofish_cbc_encrypt(&twofish_ctx, buf, buf, buf_size, iv, enc);
if (enc)
new_iv = (char*) buf + buf_size-TWOFISH_CBC_BLOCK_SIZE;
memcpy(iv, new_iv, TWOFISH_CBC_BLOCK_SIZE);
}
struct encrypt_desc encrypt_desc_twofish =
{
algo_type: IKE_ALG_ENCRYPT,
algo_id: OAKLEY_TWOFISH_CBC,
algo_next: NULL,
enc_ctxsize: sizeof(twofish_context),
enc_blocksize: TWOFISH_CBC_BLOCK_SIZE,
keydeflen: TWOFISH_KEY_MIN_LEN,
keyminlen: TWOFISH_KEY_DEF_LEN,
keymaxlen: TWOFISH_KEY_MAX_LEN,
do_crypt: do_twofish,
};
struct encrypt_desc encrypt_desc_twofish_ssh =
{
algo_type: IKE_ALG_ENCRYPT,
algo_id: OAKLEY_TWOFISH_CBC_SSH,
algo_next: NULL,
enc_ctxsize: sizeof(twofish_context),
enc_blocksize: TWOFISH_CBC_BLOCK_SIZE,
keydeflen: TWOFISH_KEY_MIN_LEN,
keyminlen: TWOFISH_KEY_DEF_LEN,
keymaxlen: TWOFISH_KEY_MAX_LEN,
do_crypt: do_twofish,
};
int ike_alg_twofish_init(void);
int
ike_alg_twofish_init(void)
{
int ret = ike_alg_register_enc(&encrypt_desc_twofish);
if (ike_alg_register_enc(&encrypt_desc_twofish_ssh) < 0)
plog("ike_alg_twofish_init(): Experimental OAKLEY_TWOFISH_CBC_SSH activation failed");
return ret;
}
/*
IKE_ALG_INIT_NAME: ike_alg_twofish_init
*/
+1197
View File
File diff suppressed because it is too large Load Diff
+85
View File
@@ -0,0 +1,85 @@
/* Algorithm info parsing and creation functions
* Author: JuanJo Ciarlante <[email protected]>
*
* 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: alg_info.h,v 1.4 2004/09/29 22:39:44 as Exp $
*/
#ifndef ALG_INFO_H
#define ALG_INFO_H
struct esp_info {
u_int8_t transid; /* ESP transform */
u_int16_t auth; /* AUTH */
size_t enckeylen; /* keylength for ESP transform */
size_t authkeylen; /* keylength for AUTH */
u_int8_t encryptalg; /* normally encryptalg=transid */
u_int8_t authalg; /* normally authalg=auth+1 */
};
struct ike_info {
u_int16_t ike_ealg; /* high 16 bit nums for reserved */
u_int8_t ike_halg;
size_t ike_eklen;
size_t ike_hklen;
u_int16_t ike_modp;
};
#define ALG_INFO_COMMON \
int alg_info_cnt; \
int ref_cnt; \
unsigned alg_info_flags; \
unsigned alg_info_protoid
struct alg_info {
ALG_INFO_COMMON;
};
struct alg_info_esp {
ALG_INFO_COMMON;
struct esp_info esp[64];
int esp_pfsgroup;
};
struct alg_info_ike {
ALG_INFO_COMMON;
struct ike_info ike[64];
};
#define esp_ealg_id transid
#define esp_aalg_id auth
#define esp_ealg_keylen enckeylen /* bits */
#define esp_aalg_keylen authkeylen /* bits */
/* alg_info_flags bits */
#define ALG_INFO_F_STRICT 0x01
extern int alg_info_esp_aa2sadb(int auth);
extern int alg_info_esp_sadb2aa(int sadb_aalg);
extern void alg_info_free(struct alg_info *alg_info);
extern void alg_info_addref(struct alg_info *alg_info);
extern void alg_info_delref(struct alg_info **alg_info);
extern struct alg_info_esp* alg_info_esp_create_from_str(const char *alg_str
, const char **err_p);
extern struct alg_info_ike* alg_info_ike_create_from_str(const char *alg_str
, const char **err_p);
extern int alg_info_parse(const char *str);
extern int alg_info_snprint(char *buf, int buflen
, struct alg_info *alg_info);
extern int alg_info_snprint_esp(char *buf, int buflen
, struct alg_info_esp *alg_info);
extern int alg_info_snprint_ike(char *buf, int buflen
, struct alg_info_ike *alg_info);
#define ALG_INFO_ESP_FOREACH(ai, ai_esp, i) \
for (i=(ai)->alg_info_cnt,ai_esp=(ai)->esp; i--; ai_esp++)
#define ALG_INFO_IKE_FOREACH(ai, ai_ike, i) \
for (i=(ai)->alg_info_cnt,ai_ike=(ai)->ike; i--; ai_ike++)
#endif /* ALG_INFO_H */
+770
View File
@@ -0,0 +1,770 @@
/* Simple ASN.1 parser
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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: asn1.c,v 1.16 2006/01/04 21:00:43 as Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "mp_defs.h"
#include "asn1.h"
#include "oid.h"
#include "log.h"
/* some common prefabricated ASN.1 constants */
static u_char ASN1_INTEGER_0_str[] = { 0x02, 0x00 };
static u_char ASN1_INTEGER_1_str[] = { 0x02, 0x01, 0x01 };
static u_char ASN1_INTEGER_2_str[] = { 0x02, 0x01, 0x02 };
const chunk_t ASN1_INTEGER_0 = strchunk(ASN1_INTEGER_0_str);
const chunk_t ASN1_INTEGER_1 = strchunk(ASN1_INTEGER_1_str);
const chunk_t ASN1_INTEGER_2 = strchunk(ASN1_INTEGER_2_str);
/* some popular algorithmIdentifiers */
static u_char ASN1_md5_id_str[] = {
0x30, 0x0C,
0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,
0x05, 0x00
};
static u_char ASN1_sha1_id_str[] = {
0x30, 0x09,
0x06, 0x05, 0x2B, 0x0E,0x03, 0x02, 0x1A,
0x05, 0x00
};
static u_char ASN1_md5WithRSA_id_str[] = {
0x30, 0x0D,
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04,
0x05, 0x00
};
static u_char ASN1_sha1WithRSA_id_str[] = {
0x30, 0x0D,
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05,
0x05, 0x00
};
static u_char ASN1_rsaEncryption_id_str[] = {
0x30, 0x0D,
0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
0x05, 0x00
};
const chunk_t ASN1_md5_id = strchunk(ASN1_md5_id_str);
const chunk_t ASN1_sha1_id = strchunk(ASN1_sha1_id_str);
const chunk_t ASN1_rsaEncryption_id = strchunk(ASN1_rsaEncryption_id_str);
const chunk_t ASN1_md5WithRSA_id = strchunk(ASN1_md5WithRSA_id_str);
const chunk_t ASN1_sha1WithRSA_id = strchunk(ASN1_sha1WithRSA_id_str);
/* ASN.1 definiton of an algorithmIdentifier */
static const asn1Object_t algorithmIdentifierObjects[] = {
{ 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
{ 1, "parameters", ASN1_EOC, ASN1_RAW } /* 2 */
};
#define ALGORITHM_ID_ALG 1
#define ALGORITHM_ID_PARAMETERS 2
#define ALGORITHM_ID_ROOF 3
/*
* return the ASN.1 encoded algorithm identifier
*/
chunk_t
asn1_algorithmIdentifier(int oid)
{
switch (oid)
{
case OID_RSA_ENCRYPTION:
return ASN1_rsaEncryption_id;
case OID_MD5_WITH_RSA:
return ASN1_md5WithRSA_id;
case OID_SHA1_WITH_RSA:
return ASN1_sha1WithRSA_id;
case OID_MD5:
return ASN1_md5_id;
case OID_SHA1:
return ASN1_sha1_id;
default:
return empty_chunk;
}
}
/* If the oid is listed in the oid_names table then the corresponding
* position in the oid_names table is returned otherwise -1 is returned
*/
int
known_oid(chunk_t object)
{
int oid = 0;
while (object.len)
{
if (oid_names[oid].octet == *object.ptr)
{
if (--object.len == 0 || oid_names[oid].down == 0)
{
return oid; /* found terminal symbol */
}
else
{
object.ptr++; oid++; /* advance to next hex octet */
}
}
else
{
if (oid_names[oid].next)
oid = oid_names[oid].next;
else
return OID_UNKNOWN;
}
}
return -1;
}
/*
* Decodes the length in bytes of an ASN.1 object
*/
u_int
asn1_length(chunk_t *blob)
{
u_char n;
size_t len;
/* advance from tag field on to length field */
blob->ptr++;
blob->len--;
/* read first octet of length field */
n = *blob->ptr++;
blob->len--;
if ((n & 0x80) == 0) /* single length octet */
return n;
/* composite length, determine number of length octets */
n &= 0x7f;
if (n > blob->len)
{
DBG(DBG_PARSING,
DBG_log("number of length octets is larger than ASN.1 object")
)
return ASN1_INVALID_LENGTH;
}
if (n > sizeof(len))
{
DBG(DBG_PARSING,
DBG_log("number of length octets is larger than limit of %d octets"
, (int)sizeof(len))
)
return ASN1_INVALID_LENGTH;
}
len = 0;
while (n-- > 0)
{
len = 256*len + *blob->ptr++;
blob->len--;
}
return len;
}
/*
* codes ASN.1 lengths up to a size of 16'777'215 bytes
*/
void
code_asn1_length(size_t length, chunk_t *code)
{
if (length < 128)
{
code->ptr[0] = length;
code->len = 1;
}
else if (length < 256)
{
code->ptr[0] = 0x81;
code->ptr[1] = (u_char) length;
code->len = 2;
}
else if (length < 65536)
{
code->ptr[0] = 0x82;
code->ptr[1] = length >> 8;
code->ptr[2] = length & 0x00ff;
code->len = 3;
}
else
{
code->ptr[0] = 0x83;
code->ptr[1] = length >> 16;
code->ptr[2] = (length >> 8) & 0x00ff;
code->ptr[3] = length & 0x0000ff;
code->len = 4;
}
}
/*
* build an empty asn.1 object with tag and length fields already filled in
*/
u_char*
build_asn1_object(chunk_t *object, asn1_t type, size_t datalen)
{
u_char length_buf[4];
chunk_t length = { length_buf, 0 };
u_char *pos;
/* code the asn.1 length field */
code_asn1_length(datalen, &length);
/* allocate memory for the asn.1 TLV object */
object->len = 1 + length.len + datalen;
object->ptr = alloc_bytes(object->len, "asn1 object");
/* set position pointer at the start of the object */
pos = object->ptr;
/* copy the asn.1 tag field and advance the pointer */
*pos++ = type;
/* copy the asn.1 length field and advance the pointer */
chunkcpy(pos, length);
return pos;
}
/*
* build a simple ASN.1 object
*/
chunk_t
asn1_simple_object(asn1_t tag, chunk_t content)
{
chunk_t object;
u_char *pos = build_asn1_object(&object, tag, content.len);
chunkcpy(pos, content);
return object;
}
/* Build an ASN.1 object from a variable number of individual chunks.
* Depending on the mode, chunks either are moved ('m') or copied ('c').
*/
chunk_t
asn1_wrap(asn1_t type, const char *mode, ...)
{
chunk_t construct;
va_list chunks;
u_char *pos;
int i;
int count = strlen(mode);
/* sum up lengths of individual chunks */
va_start(chunks, mode);
construct.len = 0;
for (i = 0; i < count; i++)
{
chunk_t ch = va_arg(chunks, chunk_t);
construct.len += ch.len;
}
va_end(chunks);
/* allocate needed memory for construct */
pos = build_asn1_object(&construct, type, construct.len);
/* copy or move the chunks */
va_start(chunks, mode);
for (i = 0; i < count; i++)
{
chunk_t ch = va_arg(chunks, chunk_t);
switch (*mode++)
{
case 'm':
mv_chunk(&pos, ch);
break;
case 'c':
default:
chunkcpy(pos, ch);
}
}
va_end(chunks);
return construct;
}
/*
* convert a MP integer into a DER coded ASN.1 object
*/
chunk_t
asn1_integer_from_mpz(const mpz_t value)
{
size_t bits = mpz_sizeinbase(value, 2); /* size in bits */
size_t size = 1 + bits / BITS_PER_BYTE; /* size in bytes */
chunk_t n = mpz_to_n(value, size);
return asn1_wrap(ASN1_INTEGER, "m", n);
}
/*
* determines if a character string is of type ASN.1 printableString
*/
bool
is_printablestring(chunk_t str)
{
const char printablestring_charset[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
u_int i;
for (i = 0; i < str.len; i++)
{
if (strchr(printablestring_charset, str.ptr[i]) == NULL)
return FALSE;
}
return TRUE;
}
/*
* Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
*/
time_t
asn1totime(const chunk_t *utctime, asn1_t type)
{
struct tm t;
time_t tz_offset;
u_char *eot = NULL;
if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
{
tz_offset = 0; /* Zulu time with a zero time zone offset */
}
else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL)
{
int tz_hour, tz_min;
sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
tz_offset = 3600*tz_hour + 60*tz_min; /* positive time zone offset */
}
else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL)
{
int tz_hour, tz_min;
sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
tz_offset = -3600*tz_hour - 60*tz_min; /* negative time zone offset */
}
else
{
return 0; /* error in time format */
}
{
const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
"%4d%2d%2d%2d%2d";
sscanf(utctime->ptr, format, &t.tm_year, &t.tm_mon, &t.tm_mday,
&t.tm_hour, &t.tm_min);
}
/* is there a seconds field? */
if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))
{
sscanf(eot-2, "%2d", &t.tm_sec);
}
else
{
t.tm_sec = 0;
}
/* representation of year */
if (t.tm_year >= 1900)
{
t.tm_year -= 1900;
}
else if (t.tm_year >= 100)
{
return 0;
}
else if (t.tm_year < 50)
{
t.tm_year += 100;
}
/* representation of month 0..11*/
t.tm_mon--;
/* set daylight saving time to off */
t.tm_isdst = 0;
/* compensate timezone */
return mktime(&t) - timezone - tz_offset;
}
/*
* convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
*/
chunk_t
timetoasn1(const time_t *time, asn1_t type)
{
int offset;
const char *format;
char buf[TIMETOA_BUF];
chunk_t formatted_time;
struct tm *t = gmtime(time);
if (type == ASN1_GENERALIZEDTIME)
{
format = "%04d%02d%02d%02d%02d%02dZ";
offset = 1900;
}
else /* ASN1_UTCTIME */
{
format = "%02d%02d%02d%02d%02d%02dZ";
offset = (t->tm_year < 100)? 0 : -100;
}
sprintf(buf, format, t->tm_year + offset, t->tm_mon + 1, t->tm_mday
, t->tm_hour, t->tm_min, t->tm_sec);
formatted_time.ptr = buf;
formatted_time.len = strlen(buf);
return asn1_simple_object(type, formatted_time);
}
/*
* Initializes the internal context of the ASN.1 parser
*/
void
asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0,
bool implicit, u_int cond)
{
ctx->blobs[0] = blob;
ctx->level0 = level0;
ctx->implicit = implicit;
ctx->cond = cond;
memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr));
}
/*
* print the value of an ASN.1 simple object
*/
static void
debug_asn1_simple_object(chunk_t object, asn1_t type, u_int cond)
{
int oid;
switch (type)
{
case ASN1_OID:
oid = known_oid(object);
if (oid != OID_UNKNOWN)
{
DBG(DBG_PARSING,
DBG_log(" '%s'",oid_names[oid].name);
)
return;
}
break;
case ASN1_UTF8STRING:
case ASN1_IA5STRING:
case ASN1_PRINTABLESTRING:
case ASN1_T61STRING:
case ASN1_VISIBLESTRING:
DBG(DBG_PARSING,
DBG_log(" '%.*s'", (int)object.len, object.ptr);
)
return;
case ASN1_UTCTIME:
case ASN1_GENERALIZEDTIME:
DBG(DBG_PARSING,
time_t time = asn1totime(&object, type);
DBG_log(" '%s'", timetoa(&time, TRUE));
)
return;
default:
break;
}
DBG(cond,
DBG_dump_chunk("", object);
)
}
/*
* Parses and extracts the next ASN.1 object
*/
bool
extract_object(asn1Object_t const *objects,
u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx)
{
asn1Object_t obj = objects[*objectID];
chunk_t *blob;
chunk_t *blob1;
u_char *start_ptr;
*object = empty_chunk;
if (obj.flags & ASN1_END) /* end of loop or option found */
{
if (ctx->loopAddr[obj.level] && ctx->blobs[obj.level+1].len > 0)
{
*objectID = ctx->loopAddr[obj.level]; /* another iteration */
obj = objects[*objectID];
}
else
{
ctx->loopAddr[obj.level] = 0; /* exit loop or option*/
return TRUE;
}
}
*level = ctx->level0 + obj.level;
blob = ctx->blobs + obj.level;
blob1 = blob + 1;
start_ptr = blob->ptr;
/* handle ASN.1 defaults values */
if ((obj.flags & ASN1_DEF)
&& (blob->len == 0 || *start_ptr != obj.type) )
{
/* field is missing */
DBG(DBG_PARSING,
DBG_log("L%d - %s:", *level, obj.name);
)
if (obj.type & ASN1_CONSTRUCTED)
{
(*objectID)++ ; /* skip context-specific tag */
}
return TRUE;
}
/* handle ASN.1 options */
if ((obj.flags & ASN1_OPT)
&& (blob->len == 0 || *start_ptr != obj.type))
{
/* advance to end of missing option field */
do
(*objectID)++;
while (!((objects[*objectID].flags & ASN1_END)
&& (objects[*objectID].level == obj.level)));
return TRUE;
}
/* an ASN.1 object must possess at least a tag and length field */
if (blob->len < 2)
{
DBG(DBG_PARSING,
DBG_log("L%d - %s: ASN.1 object smaller than 2 octets",
*level, obj.name);
)
return FALSE;
}
blob1->len = asn1_length(blob);
if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len)
{
DBG(DBG_PARSING,
DBG_log("L%d - %s: length of ASN.1 object invalid or too large",
*level, obj.name);
)
return FALSE;
}
blob1->ptr = blob->ptr;
blob->ptr += blob1->len;
blob->len -= blob1->len;
/* return raw ASN.1 object without prior type checking */
if (obj.flags & ASN1_RAW)
{
DBG(DBG_PARSING,
DBG_log("L%d - %s:", *level, obj.name);
)
object->ptr = start_ptr;
object->len = (size_t)(blob->ptr - start_ptr);
return TRUE;
}
if (*start_ptr != obj.type && !(ctx->implicit && *objectID == 0))
{
DBG(DBG_PARSING,
DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
*level, obj.name, obj.type, *start_ptr);
DBG_dump("", start_ptr, (u_int)(blob->ptr - start_ptr));
)
return FALSE;
}
DBG(DBG_PARSING,
DBG_log("L%d - %s:", ctx->level0+obj.level, obj.name);
)
/* In case of "SEQUENCE OF" or "SET OF" start a loop */
if (obj.flags & ASN1_LOOP)
{
if (blob1->len > 0)
{
/* at least one item, start the loop */
ctx->loopAddr[obj.level] = *objectID + 1;
}
else
{
/* no items, advance directly to end of loop */
do
(*objectID)++;
while (!((objects[*objectID].flags & ASN1_END)
&& (objects[*objectID].level == obj.level)));
return TRUE;
}
}
if (obj.flags & ASN1_OBJ)
{
object->ptr = start_ptr;
object->len = (size_t)(blob->ptr - start_ptr);
DBG(ctx->cond,
DBG_dump_chunk("", *object);
)
}
else if (obj.flags & ASN1_BODY)
{
*object = *blob1;
debug_asn1_simple_object(*object, obj.type, ctx->cond);
}
return TRUE;
}
/*
* parse an ASN.1 simple type
*/
bool
parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level
, const char* name)
{
size_t len;
/* an ASN.1 object must possess at least a tag and length field */
if (object->len < 2)
{
DBG(DBG_PARSING,
DBG_log("L%d - %s: ASN.1 object smaller than 2 octets",
level, name);
)
return FALSE;
}
if (*object->ptr != type)
{
DBG(DBG_PARSING,
DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
level, name, type, *object->ptr);
)
return FALSE;
}
len = asn1_length(object);
if (len == ASN1_INVALID_LENGTH || object->len < len)
{
DBG(DBG_PARSING,
DBG_log("L%d - %s: length of ASN.1 object invalid or too large",
level, name);
)
return FALSE;
}
DBG(DBG_PARSING,
DBG_log("L%d - %s:", level, name);
)
debug_asn1_simple_object(*object, type, DBG_RAW);
return TRUE;
}
/*
* extracts an algorithmIdentifier
*/
int
parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters)
{
asn1_ctx_t ctx;
chunk_t object;
u_int level;
int alg = OID_UNKNOWN;
int objectID = 0;
asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
while (objectID < ALGORITHM_ID_ROOF)
{
if (!extract_object(algorithmIdentifierObjects, &objectID, &object, &level, &ctx))
return OID_UNKNOWN;
switch (objectID)
{
case ALGORITHM_ID_ALG:
alg = known_oid(object);
break;
case ALGORITHM_ID_PARAMETERS:
if (parameters != NULL)
*parameters = object;
break;
default:
break;
}
objectID++;
}
return alg;
}
/*
* tests if a blob contains a valid ASN.1 set or sequence
*/
bool
is_asn1(chunk_t blob)
{
u_int len;
u_char tag = *blob.ptr;
if (tag != ASN1_SEQUENCE && tag != ASN1_SET)
{
DBG(DBG_PARSING,
DBG_log(" file content is not binary ASN.1");
)
return FALSE;
}
len = asn1_length(&blob);
if (len != blob.len)
{
DBG(DBG_PARSING,
DBG_log(" file size does not match ASN.1 coded length");
)
return FALSE;
}
return TRUE;
}
+141
View File
@@ -0,0 +1,141 @@
/* Simple ASN.1 parser
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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: asn1.h,v 1.14 2005/12/06 22:50:10 as Exp $
*/
#ifndef _ASN1_H
#define _ASN1_H
#include <stdarg.h>
#include <gmp.h>
#include "defs.h"
/* Defines some primitive ASN1 types */
typedef enum {
ASN1_EOC = 0x00,
ASN1_BOOLEAN = 0x01,
ASN1_INTEGER = 0x02,
ASN1_BIT_STRING = 0x03,
ASN1_OCTET_STRING = 0x04,
ASN1_NULL = 0x05,
ASN1_OID = 0x06,
ASN1_ENUMERATED = 0x0A,
ASN1_UTF8STRING = 0x0C,
ASN1_NUMERICSTRING = 0x12,
ASN1_PRINTABLESTRING = 0x13,
ASN1_T61STRING = 0x14,
ASN1_VIDEOTEXSTRING = 0x15,
ASN1_IA5STRING = 0x16,
ASN1_UTCTIME = 0x17,
ASN1_GENERALIZEDTIME = 0x18,
ASN1_GRAPHICSTRING = 0x19,
ASN1_VISIBLESTRING = 0x1A,
ASN1_GENERALSTRING = 0x1B,
ASN1_UNIVERSALSTRING = 0x1C,
ASN1_BMPSTRING = 0x1E,
ASN1_CONSTRUCTED = 0x20,
ASN1_SEQUENCE = 0x30,
ASN1_SET = 0x31,
ASN1_CONTEXT_S_0 = 0x80,
ASN1_CONTEXT_S_1 = 0x81,
ASN1_CONTEXT_S_2 = 0x82,
ASN1_CONTEXT_S_3 = 0x83,
ASN1_CONTEXT_S_4 = 0x84,
ASN1_CONTEXT_S_5 = 0x85,
ASN1_CONTEXT_S_6 = 0x86,
ASN1_CONTEXT_S_7 = 0x87,
ASN1_CONTEXT_S_8 = 0x88,
ASN1_CONTEXT_C_0 = 0xA0,
ASN1_CONTEXT_C_1 = 0xA1,
ASN1_CONTEXT_C_2 = 0xA2,
ASN1_CONTEXT_C_3 = 0xA3,
ASN1_CONTEXT_C_4 = 0xA4,
ASN1_CONTEXT_C_5 = 0xA5
} asn1_t;
/* Definition of ASN1 flags */
#define ASN1_NONE 0x00
#define ASN1_DEF 0x01
#define ASN1_OPT 0x02
#define ASN1_LOOP 0x04
#define ASN1_END 0x08
#define ASN1_OBJ 0x10
#define ASN1_BODY 0x20
#define ASN1_RAW 0x40
#define ASN1_INVALID_LENGTH 0xffffffff
/* definition of an ASN.1 object */
typedef struct {
u_int level;
const u_char *name;
asn1_t type;
u_char flags;
} asn1Object_t;
#define ASN1_MAX_LEVEL 10
typedef struct {
bool implicit;
u_int cond;
u_int level0;
u_int loopAddr[ASN1_MAX_LEVEL+1];
chunk_t blobs[ASN1_MAX_LEVEL+2];
} asn1_ctx_t;
/* some common prefabricated ASN.1 constants */
extern const chunk_t ASN1_INTEGER_0;
extern const chunk_t ASN1_INTEGER_1;
extern const chunk_t ASN1_INTEGER_2;
/* some popular algorithmIdentifiers */
extern const chunk_t ASN1_md5_id;
extern const chunk_t ASN1_sha1_id;
extern const chunk_t ASN1_rsaEncryption_id;
extern const chunk_t ASN1_md5WithRSA_id;
extern const chunk_t ASN1_sha1WithRSA_id;
extern chunk_t asn1_algorithmIdentifier(int oid);
extern int known_oid(chunk_t object);
extern u_int asn1_length(chunk_t *blob);
extern void code_asn1_length(size_t length, chunk_t *code);
extern u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen);
extern chunk_t asn1_integer_from_mpz(const mpz_t value);
extern chunk_t asn1_simple_object(asn1_t tag, chunk_t content);
extern chunk_t asn1_wrap(asn1_t type, const char *mode, ...);
extern bool is_printablestring(chunk_t str);
extern time_t asn1totime(const chunk_t *utctime, asn1_t type);
extern chunk_t timetoasn1(const time_t *time, asn1_t type);
extern void asn1_init(asn1_ctx_t *ctx, chunk_t blob
, u_int level0, bool implicit, u_int cond);
extern bool extract_object(asn1Object_t const *objects
, u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx);
extern bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level
, const char* name);
extern int parse_algorithmIdentifier(chunk_t blob, int level0
, chunk_t *parameters);
extern bool is_asn1(chunk_t blob);
#endif /* _ASN1_H */
+694
View File
@@ -0,0 +1,694 @@
/* Certification Authority (CA) support for IKE authentication
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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: ca.c,v 1.10 2005/12/25 12:29:55 as Exp $
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
#include <sys/types.h>
#include <freeswan.h>
#include <freeswan/ipsec_policy.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "x509.h"
#include "ca.h"
#include "certs.h"
#include "whack.h"
#include "fetch.h"
/* chained list of X.509 authority certificates (ca, aa, and ocsp) */
static x509cert_t *x509authcerts = NULL;
const ca_info_t empty_ca_info = {
NULL , /* next */
NULL , /* name */
UNDEFINED_TIME,
{ NULL, 0 } , /* authName */
{ NULL, 0 } , /* authKeyID */
{ NULL, 0 } , /* authKey SerialNumber */
NULL , /* ldaphost */
NULL , /* ldapbase */
NULL , /* ocspori */
NULL , /* crluri */
FALSE /* strictcrlpolicy */
};
/* chained list of X.509 certification authority information records */
static ca_info_t *ca_infos = NULL;
/*
* Checks if CA a is trusted by CA b
*/
bool
trusted_ca(chunk_t a, chunk_t b, int *pathlen)
{
bool match = FALSE;
/* no CA b specified -> any CA a is accepted */
if (b.ptr == NULL)
{
*pathlen = (a.ptr == NULL)? 0 : MAX_CA_PATH_LEN;
return TRUE;
}
/* no CA a specified -> trust cannot be established */
if (a.ptr == NULL)
{
*pathlen = MAX_CA_PATH_LEN;
return FALSE;
}
*pathlen = 0;
/* CA a equals CA b -> we have a match */
if (same_dn(a, b))
return TRUE;
/* CA a might be a subordinate CA of b */
lock_authcert_list("trusted_ca");
while ((*pathlen)++ < MAX_CA_PATH_LEN)
{
x509cert_t *cacert = get_authcert(a, empty_chunk, empty_chunk, AUTH_CA);
/* cacert not found or self-signed root cacert-> exit */
if (cacert == NULL || same_dn(cacert->issuer, a))
break;
/* does the issuer of CA a match CA b? */
match = same_dn(cacert->issuer, b);
/* we have a match and exit the loop */
if (match)
break;
/* go one level up in the CA chain */
a = cacert->issuer;
}
unlock_authcert_list("trusted_ca");
return match;
}
/*
* does our CA match one of the requested CAs?
*/
bool
match_requested_ca(generalName_t *requested_ca, chunk_t our_ca, int *our_pathlen)
{
/* if no ca is requested than any ca will match */
if (requested_ca == NULL)
{
*our_pathlen = 0;
return TRUE;
}
*our_pathlen = MAX_CA_PATH_LEN + 1;
while (requested_ca != NULL)
{
int pathlen;
if (trusted_ca(our_ca, requested_ca->name, &pathlen)
&& pathlen < *our_pathlen)
*our_pathlen = pathlen;
requested_ca = requested_ca->next;
}
return *our_pathlen <= MAX_CA_PATH_LEN;
}
/*
* free the first authority certificate in the chain
*/
static void
free_first_authcert(void)
{
x509cert_t *first = x509authcerts;
x509authcerts = first->next;
free_x509cert(first);
}
/*
* free all CA certificates
*/
void
free_authcerts(void)
{
lock_authcert_list("free_authcerts");
while (x509authcerts != NULL)
free_first_authcert();
unlock_authcert_list("free_authcerts");
}
/*
* get a X.509 authority certificate with a given subject or keyid
*/
x509cert_t*
get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid, u_char auth_flags)
{
x509cert_t *cert = x509authcerts;
x509cert_t *prev_cert = NULL;
while (cert != NULL)
{
if (cert->authority_flags & auth_flags
&& ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID)
: (same_dn(subject, cert->subject)
&& same_serial(serial, cert->serialNumber))))
{
if (cert != x509authcerts)
{
/* bring the certificate up front */
prev_cert->next = cert->next;
cert->next = x509authcerts;
x509authcerts = cert;
}
return cert;
}
prev_cert = cert;
cert = cert->next;
}
return NULL;
}
/*
* add an authority certificate to the chained list
*/
bool
add_authcert(x509cert_t *cert, u_char auth_flags)
{
x509cert_t *old_cert;
/* set authority flags */
cert->authority_flags |= auth_flags;
lock_authcert_list("add_authcert");
old_cert = get_authcert(cert->subject, cert->serialNumber
, cert->subjectKeyID, auth_flags);
if (old_cert != NULL)
{
if (same_x509cert(cert, old_cert))
{
/* cert is already present, just add additional authority flags */
old_cert->authority_flags |= cert->authority_flags;
DBG(DBG_CONTROL | DBG_PARSING ,
DBG_log(" authcert is already present and identical")
)
unlock_authcert_list("add_authcert");
free_x509cert(cert);
return FALSE;
}
else
{
/* cert is already present but will be replaced by new cert */
free_first_authcert();
DBG(DBG_CONTROL | DBG_PARSING ,
DBG_log(" existing authcert deleted")
)
}
}
/* add new authcert to chained list */
cert->next = x509authcerts;
x509authcerts = cert;
share_x509cert(cert); /* set count to one */
DBG(DBG_CONTROL | DBG_PARSING,
DBG_log(" authcert inserted")
)
unlock_authcert_list("add_authcert");
return TRUE;
}
/*
* Loads authority certificates
*/
void
load_authcerts(const char *type, const char *path, u_char auth_flags)
{
struct dirent **filelist;
u_char buf[BUF_LEN];
u_char *save_dir;
int n;
/* change directory to specified path */
save_dir = getcwd(buf, BUF_LEN);
if (chdir(path))
{
plog("Could not change to directory '%s'", path);
}
else
{
plog("Changing to directory '%s'", path);
n = scandir(path, &filelist, file_select, alphasort);
if (n < 0)
plog(" scandir() error");
else
{
while (n--)
{
cert_t cert;
if (load_cert(filelist[n]->d_name, type, &cert))
add_authcert(cert.u.x509, auth_flags);
free(filelist[n]);
}
free(filelist);
}
}
/* restore directory path */
chdir(save_dir);
}
/*
* list all X.509 authcerts with given auth flags in a chained list
*/
void
list_authcerts(const char *caption, u_char auth_flags, bool utc)
{
lock_authcert_list("list_authcerts");
list_x509cert_chain(caption, x509authcerts, auth_flags, utc);
unlock_authcert_list("list_authcerts");
}
/*
* get a cacert with a given subject or keyid from an alternative list
*/
static const x509cert_t*
get_alt_cacert(chunk_t subject, chunk_t serial, chunk_t keyid
, const x509cert_t *cert)
{
while (cert != NULL)
{
if ((keyid.ptr != NULL) ? same_keyid(keyid, cert->subjectKeyID)
: (same_dn(subject, cert->subject)
&& same_serial(serial, cert->serialNumber)))
{
return cert;
}
cert = cert->next;
}
return NULL;
}
/* establish trust into a candidate authcert by going up the trust chain.
* validity and revocation status are not checked.
*/
bool
trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain)
{
int pathlen;
lock_authcert_list("trust_authcert_candidate");
for (pathlen = 0; pathlen < MAX_CA_PATH_LEN; pathlen++)
{
const x509cert_t *authcert = NULL;
u_char buf[BUF_LEN];
DBG(DBG_CONTROL,
dntoa(buf, BUF_LEN, cert->subject);
DBG_log("subject: '%s'",buf);
dntoa(buf, BUF_LEN, cert->issuer);
DBG_log("issuer: '%s'",buf);
if (cert->authKeyID.ptr != NULL)
{
datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
, buf, BUF_LEN);
DBG_log("authkey: %s", buf);
}
)
/* search in alternative chain first */
authcert = get_alt_cacert(cert->issuer, cert->authKeySerialNumber
, cert->authKeyID, alt_chain);
if (authcert != NULL)
{
DBG(DBG_CONTROL,
DBG_log("issuer cacert found in alternative chain")
)
}
else
{
/* search in trusted chain */
authcert = get_authcert(cert->issuer, cert->authKeySerialNumber
, cert->authKeyID, AUTH_CA);
if (authcert != NULL)
{
DBG(DBG_CONTROL,
DBG_log("issuer cacert found")
)
}
else
{
plog("issuer cacert not found");
unlock_authcert_list("trust_authcert_candidate");
return FALSE;
}
}
if (!check_signature(cert->tbsCertificate, cert->signature
, cert->algorithm, cert->algorithm, authcert))
{
plog("certificate signature is invalid");
unlock_authcert_list("trust_authcert_candidate");
return FALSE;
}
DBG(DBG_CONTROL,
DBG_log("certificate signature is valid")
)
/* check if cert is a self-signed root ca */
if (pathlen > 0 && same_dn(cert->issuer, cert->subject))
{
DBG(DBG_CONTROL,
DBG_log("reached self-signed root ca")
)
unlock_authcert_list("trust_authcert_candidate");
return TRUE;
}
/* go up one step in the trust chain */
cert = authcert;
}
plog("maximum ca path length of %d levels exceeded", MAX_CA_PATH_LEN);
unlock_authcert_list("trust_authcert_candidate");
return FALSE;
}
/*
* get a CA info record with a given authName or authKeyID
*/
ca_info_t*
get_ca_info(chunk_t authname, chunk_t serial, chunk_t keyid)
{
ca_info_t *ca= ca_infos;
while (ca!= NULL)
{
if ((keyid.ptr != NULL) ? same_keyid(keyid, ca->authKeyID)
: (same_dn(authname, ca->authName)
&& same_serial(serial, ca->authKeySerialNumber)))
{
return ca;
}
ca = ca->next;
}
return NULL;
}
/*
* free the dynamic memory used by a ca_info record
*/
static void
free_ca_info(ca_info_t* ca_info)
{
if (ca_info == NULL)
return;
pfreeany(ca_info->name);
pfreeany(ca_info->ldaphost);
pfreeany(ca_info->ldapbase);
pfreeany(ca_info->ocspuri);
freeanychunk(ca_info->authName);
freeanychunk(ca_info->authKeyID);
freeanychunk(ca_info->authKeySerialNumber);
free_generalNames(ca_info->crluri, TRUE);
pfree(ca_info);
}
/*
* free all CA certificates
*/
void
free_ca_infos(void)
{
while (ca_infos != NULL)
{
ca_info_t *ca = ca_infos;
ca_infos = ca_infos->next;
free_ca_info(ca);
}
}
/*
* find a CA information record by name and optionally delete it
*/
bool
find_ca_info_by_name(const char *name, bool delete)
{
ca_info_t **ca_p = &ca_infos;
ca_info_t *ca = *ca_p;
while (ca != NULL)
{
/* is there already an entry? */
if (streq(name, ca->name))
{
if (delete)
{
lock_ca_info_list("find_ca_info_by_name");
*ca_p = ca->next;
free_ca_info(ca);
plog("deleting ca description \"%s\"", name);
unlock_ca_info_list("find_ca_info_by_name");
}
return TRUE;
}
ca_p = &ca->next;
ca = *ca_p;
}
return FALSE;
}
/*
* adds a CA description to a chained list
*/
void
add_ca_info(const whack_message_t *msg)
{
smartcard_t *sc = NULL;
cert_t cert;
bool valid_cert = FALSE;
bool cached_cert = FALSE;
if (find_ca_info_by_name(msg->name, FALSE))
{
loglog(RC_DUPNAME, "attempt to redefine ca record \"%s\"", msg->name);
return;
}
if (scx_on_smartcard(msg->cacert))
{
/* load CA cert from smartcard */
valid_cert = scx_load_cert(msg->cacert, &sc, &cert, &cached_cert);
}
else
{
/* load CA cert from file */
valid_cert = load_ca_cert(msg->cacert, &cert);
}
if (valid_cert)
{
char buf[BUF_LEN];
x509cert_t *cacert = cert.u.x509;
ca_info_t *ca = NULL;
/* does the authname already exist? */
ca = get_ca_info(cacert->subject, cacert->serialNumber
, cacert->subjectKeyID);
if (ca != NULL)
{
/* ca_info is already present */
loglog(RC_DUPNAME, " duplicate ca information in record \"%s\" found,"
"ignoring \"%s\"", ca->name, msg->name);
free_x509cert(cacert);
return;
}
plog("added ca description \"%s\"", msg->name);
/* create and initialize new ca_info record */
ca = alloc_thing(ca_info_t, "ca info");
*ca = empty_ca_info;
/* name */
ca->name = clone_str(msg->name, "ca name");
/* authName */
clonetochunk(ca->authName, cacert->subject.ptr
, cacert->subject.len, "authName");
dntoa(buf, BUF_LEN, ca->authName);
DBG(DBG_CONTROL,
DBG_log("authname: '%s'", buf)
)
/* authSerialNumber */
clonetochunk(ca->authKeySerialNumber, cacert->serialNumber.ptr
, cacert->serialNumber.len, "authKeySerialNumber");
/* authKeyID */
if (cacert->subjectKeyID.ptr != NULL)
{
clonetochunk(ca->authKeyID, cacert->subjectKeyID.ptr
, cacert->subjectKeyID.len, "authKeyID");
datatot(cacert->subjectKeyID.ptr, cacert->subjectKeyID.len, ':'
, buf, BUF_LEN);
DBG(DBG_CONTROL | DBG_PARSING ,
DBG_log("authkey: %s", buf)
)
}
/* ldaphost */
ca->ldaphost = clone_str(msg->ldaphost, "ldaphost");
/* ldapbase */
ca->ldapbase = clone_str(msg->ldapbase, "ldapbase");
/* ocspuri */
if (msg->ocspuri != NULL)
{
if (strncasecmp(msg->ocspuri, "http", 4) == 0)
ca->ocspuri = clone_str(msg->ocspuri, "ocspuri");
else
plog(" ignoring ocspuri with unkown protocol");
}
/* crluri2*/
if (msg->crluri2 != NULL)
{
generalName_t gn =
{ NULL, GN_URI, {msg->crluri2, strlen(msg->crluri2)} };
add_distribution_points(&gn, &ca->crluri);
}
/* crluri */
if (msg->crluri != NULL)
{
generalName_t gn =
{ NULL, GN_URI, {msg->crluri, strlen(msg->crluri)} };
add_distribution_points(&gn, &ca->crluri);
}
/* strictrlpolicy */
ca->strictcrlpolicy = msg->whack_strict;
/* insert ca_info record into the chained list */
lock_ca_info_list("add_ca_info");
ca->next = ca_infos;
ca_infos = ca;
ca->installed = time(NULL);
unlock_ca_info_list("add_ca_info");
/* add cacert to list of authcerts */
if (!cached_cert)
{
if (add_authcert(cacert, AUTH_CA) && sc != NULL)
{
if (sc->last_cert.type == CERT_X509_SIGNATURE)
sc->last_cert.u.x509->count--;
sc->last_cert = cert;
share_cert(sc->last_cert);
}
}
if (sc != NULL)
time(&sc->last_load);
}
}
/*
* list all ca_info records in the chained list
*/
void
list_ca_infos(bool utc)
{
ca_info_t *ca = ca_infos;
if (ca != NULL)
{
whack_log(RC_COMMENT, " ");
whack_log(RC_COMMENT, "List of X.509 CA Information Records:");
whack_log(RC_COMMENT, " ");
}
while (ca != NULL)
{
u_char buf[BUF_LEN];
/* strictpolicy per CA not supported yet
*
whack_log(RC_COMMENT, "%s, \"%s\", strictcrlpolicy: %s"
, timetoa(&ca->installed, utc), ca->name
, ca->strictcrlpolicy? "yes":"no");
*/
whack_log(RC_COMMENT, "%s, \"%s\"", timetoa(&ca->installed, utc), ca->name);
dntoa(buf, BUF_LEN, ca->authName);
whack_log(RC_COMMENT, " authname: '%s'", buf);
if (ca->ldaphost != NULL)
whack_log(RC_COMMENT, " ldaphost: '%s'", ca->ldaphost);
if (ca->ldapbase != NULL)
whack_log(RC_COMMENT, " ldapbase: '%s'", ca->ldapbase);
if (ca->ocspuri != NULL)
whack_log(RC_COMMENT, " ocspuri: '%s'", ca->ocspuri);
list_distribution_points(ca->crluri);
if (ca->authKeyID.ptr != NULL)
{
datatot(ca->authKeyID.ptr, ca->authKeyID.len, ':'
, buf, BUF_LEN);
whack_log(RC_COMMENT, " authkey: %s", buf);
}
if (ca->authKeySerialNumber.ptr != NULL)
{
datatot(ca->authKeySerialNumber.ptr, ca->authKeySerialNumber.len, ':'
, buf, BUF_LEN);
whack_log(RC_COMMENT, " aserial: %s", buf);
}
ca = ca->next;
}
}
+70
View File
@@ -0,0 +1,70 @@
/* Certification Authority (CA) support for IKE authentication
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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: ca.h,v 1.5 2005/12/25 12:28:40 as Exp $
*/
#ifndef _CA_H
#define _CA_H
#include "x509.h"
#include "whack.h"
#define MAX_CA_PATH_LEN 7
/* authority flags */
#define AUTH_NONE 0x00 /* no authorities */
#define AUTH_CA 0x01 /* certification authority */
#define AUTH_AA 0x02 /* authorization authority */
#define AUTH_OCSP 0x04 /* ocsp signing authority */
/* CA info structures */
typedef struct ca_info ca_info_t;
struct ca_info {
ca_info_t *next;
char *name;
time_t installed;
chunk_t authName;
chunk_t authKeyID;
chunk_t authKeySerialNumber;
char *ldaphost;
char *ldapbase;
char *ocspuri;
generalName_t *crluri;
bool strictcrlpolicy;
};
extern bool trusted_ca(chunk_t a, chunk_t b, int *pathlen);
extern bool match_requested_ca(generalName_t *requested_ca
, chunk_t our_ca, int *our_pathlen);
extern x509cert_t* get_authcert(chunk_t subject, chunk_t serial, chunk_t keyid
, u_char auth_flags);
extern void load_authcerts(const char *type, const char *path
, u_char auth_flags);
extern bool add_authcert(x509cert_t *cert, u_char auth_flags);
extern void free_authcerts(void);
extern void list_authcerts(const char *caption, u_char auth_flags, bool utc);
extern bool trust_authcert_candidate(const x509cert_t *cert
, const x509cert_t *alt_chain);
extern ca_info_t* get_ca_info(chunk_t name, chunk_t serial, chunk_t keyid);
extern bool find_ca_info_by_name(const char *name, bool delete);
extern void add_ca_info(const whack_message_t *msg);
extern void delete_ca_info(const char *name);
extern void free_ca_infos(void);
extern void list_ca_infos(bool utc);
#endif /* _CA_H */
+287
View File
@@ -0,0 +1,287 @@
/* Certificate support for IKE authentication
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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: certs.c,v 1.8 2005/11/06 22:55:41 as Exp $
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <freeswan.h>
#include <freeswan/ipsec_policy.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "asn1.h"
#include "id.h"
#include "x509.h"
#include "pgp.h"
#include "pem.h"
#include "certs.h"
#include "pkcs1.h"
/*
* used for initializatin of certs
*/
const cert_t empty_cert = {CERT_NONE, {NULL}};
/*
* extracts the certificate to be sent to the peer
*/
chunk_t
get_mycert(cert_t cert)
{
switch (cert.type)
{
case CERT_PGP:
return cert.u.pgp->certificate;
case CERT_X509_SIGNATURE:
return cert.u.x509->certificate;
default:
return empty_chunk;
}
}
/* load a coded key or certificate file with autodetection
* of binary DER or base64 PEM ASN.1 formats and armored PGP format
*/
bool
load_coded_file(const char *filename, prompt_pass_t *pass, const char *type
, chunk_t *blob, bool *pgp)
{
err_t ugh = NULL;
FILE *fd = fopen(filename, "r");
if (fd)
{
int bytes;
fseek(fd, 0, SEEK_END );
blob->len = ftell(fd);
rewind(fd);
blob->ptr = alloc_bytes(blob->len, type);
bytes = fread(blob->ptr, 1, blob->len, fd);
fclose(fd);
plog(" loaded %s file '%s' (%d bytes)", type, filename, bytes);
*pgp = FALSE;
/* try DER format */
if (is_asn1(*blob))
{
DBG(DBG_PARSING,
DBG_log(" file coded in DER format");
)
return TRUE;
}
/* try PEM format */
ugh = pemtobin(blob, pass, filename, pgp);
if (ugh == NULL)
{
if (*pgp)
{
DBG(DBG_PARSING,
DBG_log(" file coded in armored PGP format");
)
return TRUE;
}
if (is_asn1(*blob))
{
DBG(DBG_PARSING,
DBG_log(" file coded in PEM format");
)
return TRUE;
}
ugh = "file coded in unknown format, discarded";
}
/* a conversion error has occured */
plog(" %s", ugh);
pfree(blob->ptr);
*blob = empty_chunk;
}
else
{
plog(" could not open %s file '%s'", type, filename);
}
return FALSE;
}
/*
* Loads a PKCS#1 or PGP private RSA key file
*/
err_t
load_rsa_private_key(const char* filename, prompt_pass_t *pass
, RSA_private_key_t *key)
{
err_t ugh = NULL;
bool pgp = FALSE;
chunk_t blob = empty_chunk;
const char *path = concatenate_paths(PRIVATE_KEY_PATH, filename);
if (load_coded_file(path, pass, "private key", &blob, &pgp))
{
if (pgp)
{
if (!parse_pgp(blob, NULL, key))
ugh = "syntax error in PGP private key file";
}
else
{
if (!pkcs1_parse_private_key(blob, key))
ugh = "syntax error in PKCS#1 private key file";
}
pfree(blob.ptr);
}
else
ugh = "error loading RSA private key file";
return ugh;
}
/*
* Loads a X.509 or OpenPGP certificate
*/
bool
load_cert(const char *filename, const char *label, cert_t *cert)
{
bool pgp = FALSE;
chunk_t blob = empty_chunk;
/* initialize cert struct */
cert->type = CERT_NONE;
cert->u.x509 = NULL;
if (load_coded_file(filename, NULL, label, &blob, &pgp))
{
if (pgp)
{
pgpcert_t *pgpcert = alloc_thing(pgpcert_t, "pgpcert");
*pgpcert = empty_pgpcert;
if (parse_pgp(blob, pgpcert, NULL))
{
cert->type = CERT_PGP;
cert->u.pgp = pgpcert;
return TRUE;
}
else
{
plog(" error in OpenPGP certificate");
free_pgpcert(pgpcert);
return FALSE;
}
}
else
{
x509cert_t *x509cert = alloc_thing(x509cert_t, "x509cert");
*x509cert = empty_x509cert;
if (parse_x509cert(blob, 0, x509cert))
{
cert->type = CERT_X509_SIGNATURE;
cert->u.x509 = x509cert;
return TRUE;
}
else
{
plog(" error in X.509 certificate");
free_x509cert(x509cert);
return FALSE;
}
}
}
return FALSE;
}
/*
* Loads a host certificate
*/
bool
load_host_cert(const char *filename, cert_t *cert)
{
const char *path = concatenate_paths(HOST_CERT_PATH, filename);
return load_cert(path, "host cert", cert);
}
/*
* Loads a CA certificate
*/
bool
load_ca_cert(const char *filename, cert_t *cert)
{
const char *path = concatenate_paths(CA_CERT_PATH, filename);
return load_cert(path, "CA cert", cert);
}
/*
* establish equality of two certificates
*/
bool
same_cert(const cert_t *a, const cert_t *b)
{
return a->type == b->type && a->u.x509 == b->u.x509;
}
/* for each link pointing to the certif icate
" increase the count by one
*/
void
share_cert(cert_t cert)
{
switch (cert.type)
{
case CERT_PGP:
share_pgpcert(cert.u.pgp);
break;
case CERT_X509_SIGNATURE:
share_x509cert(cert.u.x509);
break;
default:
break;
}
}
/* release of a certificate decreases the count by one
" the certificate is freed when the counter reaches zero
*/
void
release_cert(cert_t cert)
{
switch (cert.type)
{
case CERT_PGP:
release_pgpcert(cert.u.pgp);
break;
case CERT_X509_SIGNATURE:
release_x509cert(cert.u.x509);
break;
default:
break;
}
}
/*
* list all X.509 and OpenPGP end certificates
*/
void
list_certs(bool utc)
{
list_x509_end_certs(utc);
list_pgp_end_certs(utc);
}
+80
View File
@@ -0,0 +1,80 @@
/* Certificate support for IKE authentication
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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: certs.h,v 1.7 2005/11/06 22:55:41 as Exp $
*/
#ifndef _CERTS_H
#define _CERTS_H
#include "pkcs1.h"
#include "x509.h"
#include "pgp.h"
/* path definitions for private keys, end certs,
* cacerts, attribute certs and crls
*/
#define PRIVATE_KEY_PATH "/etc/ipsec.d/private"
#define HOST_CERT_PATH "/etc/ipsec.d/certs"
#define CA_CERT_PATH "/etc/ipsec.d/cacerts"
#define A_CERT_PATH "/etc/ipsec.d/acerts"
#define AA_CERT_PATH "/etc/ipsec.d/aacerts"
#define OCSP_CERT_PATH "/etc/ipsec.d/ocspcerts"
#define CRL_PATH "/etc/ipsec.d/crls"
#define REQ_PATH "/etc/ipsec.d/reqs"
/* advance warning of imminent expiry of
* cacerts, public keys, and crls
*/
#define CA_CERT_WARNING_INTERVAL 30 /* days */
#define OCSP_CERT_WARNING_INTERVAL 30 /* days */
#define PUBKEY_WARNING_INTERVAL 7 /* days */
#define CRL_WARNING_INTERVAL 7 /* days */
#define ACERT_WARNING_INTERVAL 1 /* day */
/* certificate access structure
* currently X.509 and OpenPGP certificates are supported
*/
typedef struct {
u_char type;
union {
x509cert_t *x509;
pgpcert_t *pgp;
} u;
} cert_t;
/* used for initialization */
extern const cert_t empty_cert;
/* do not send certificate requests
* flag set in plutomain.c and used in ipsec_doi.c
*/
extern bool no_cr_send;
extern err_t load_rsa_private_key(const char* filename, prompt_pass_t *pass
, RSA_private_key_t *key);
extern chunk_t get_mycert(cert_t cert);
extern bool load_coded_file(const char *filename, prompt_pass_t *pass
, const char *type, chunk_t *blob, bool *pgp);
extern bool load_cert(const char *filename, const char *label
, cert_t *cert);
extern bool load_host_cert(const char *filename, cert_t *cert);
extern bool load_ca_cert(const char *filename, cert_t *cert);
extern bool same_cert(const cert_t *a, const cert_t *b);
extern void share_cert(cert_t cert);
extern void release_cert(cert_t cert);
extern void list_certs(bool utc);
#endif /* _CERTS_H */
File diff suppressed because it is too large Load Diff
+375
View File
@@ -0,0 +1,375 @@
/* information about connections between hosts and clients
* Copyright (C) 1998-2001 D. Hugh Redelmeier
*
* 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: connections.h,v 1.18 2006/04/22 21:59:20 as Exp $
*/
#ifndef _CONNECTIONS_H
#define _CONNECTIONS_H
#include <sys/queue.h>
#include "id.h"
#include "certs.h"
#include "ac.h"
#include "smartcard.h"
#include "whack.h"
/* There are two kinds of connections:
* - ISAKMP connections, between hosts (for IKE communication)
* - IPsec connections, between clients (for secure IP communication)
*
* An ISAKMP connection looks like:
* host<--->host
*
* An IPsec connection looks like:
* client-subnet<-->host<->nexthop<--->nexthop<->host<-->client-subnet
*
* For the connection to be relevant to this instance of Pluto,
* exactly one of the hosts must be a public interface of our machine
* known to this instance.
*
* The client subnet might simply be the host -- this is a
* representation of "host mode".
*
* Each nexthop defaults to the neighbouring host's IP address.
* The nexthop is a property of the pair of hosts, not each
* individually. It is only needed for IPsec because of the
* way IPsec is mixed into the kernel routing logic. Furthermore,
* only this end's nexthop is actually used. Eventually, nexthop
* will be unnecessary.
*
* Other information represented:
* - each connection has a name: a chunk of uninterpreted text
* that is unique for each connection.
* - security requirements (currently just the "policy" flags from
* the whack command to initiate the connection, but eventually
* much more. Different for ISAKMP and IPsec connections.
* - rekeying parameters:
* + time an SA may live
* + time before SA death that a rekeying should be attempted
* (only by the initiator)
* + number of times to attempt rekeying
* - With the current KLIPS, we must route packets for a client
* subnet through the ipsec interface (ipsec0). Only one
* gateway can get traffic for a specific (client) subnet.
* Furthermore, if the routing isn't in place, packets will
* be sent in the clear.
* "routing" indicates whether the routing has been done for
* this connection. Note that several connections may claim
* the same routing, as long as they agree about where the
* packets are to be sent.
* - With the current KLIPS, only one outbound IPsec SA bundle can be
* used for a particular client. This is due to a limitation
* of using only routing for selection. So only one IPsec state (SA)
* may "own" the eroute. "eroute_owner" is the serial number of
* this state, SOS_NOBODY if there is none. "routing" indicates
* what kind of erouting has been done for this connection, if any.
*
* Details on routing is in constants.h
*
* Operations on Connections:
*
* - add a new connection (with all details) [whack command]
* - delete a connection (by name) [whack command]
* - initiate a connection (by name) [whack command]
* - find a connection (by IP addresses of hosts)
* [response to peer request; finding ISAKMP connection for IPsec connection]
*
* Some connections are templates, missing the address of the peer
* (represented by INADDR_ANY). These are always arranged so that the
* missing end is "that" (there can only be one missing end). These can
* be instantiated (turned into real connections) by Pluto in one of two
* different ways: Road Warrior Instantiation or Opportunistic
* Instantiation. A template connection is marked for Opportunistic
* Instantiation by specifying the peer client as 0.0.0.0/32 (or the IPV6
* equivalent). Otherwise, it is suitable for Road Warrior Instantiation.
*
* Instantiation creates a new temporary connection, with the missing
* details filled in. The resulting template lasts only as long as there
* is a state that uses it.
*/
/* connection policy priority: how important this policy is
* - used to implement eroute-like precedence (augmented by a small
* bonus for a routed connection).
* - a whole number
* - larger is more important
* - three subcomponents. In order of decreasing significance:
* + length of source subnet mask (8 bits)
* + length of destination subnet mask (8 bits)
* + bias (8 bit)
* - a bias of 1 is added to allow prio BOTTOM_PRIO to be less than all
* normal priorities
* - other bias values are created on the fly to give mild preference
* to certaion conditions (eg. routedness)
* - priority is inherited -- an instance of a policy has the same priority
* as the original policy, even though its subnets might be smaller.
* - display format: n,m
*/
typedef unsigned long policy_prio_t;
#define BOTTOM_PRIO ((policy_prio_t)0) /* smaller than any real prio */
#define set_policy_prio(c) { (c)->prio = \
((policy_prio_t)(c)->spd.this.client.maskbits << 16) \
| ((policy_prio_t)(c)->spd.that.client.maskbits << 8) \
| (policy_prio_t)1; }
#define POLICY_PRIO_BUF (3+1+3+1)
extern void fmt_policy_prio(policy_prio_t pp, char buf[POLICY_PRIO_BUF]);
#ifdef VIRTUAL_IP
struct virtual_t;
#endif
struct end {
struct id id;
ip_address
host_addr,
host_nexthop,
host_srcip;
ip_subnet client;
bool key_from_DNS_on_demand;
bool has_client;
bool has_client_wildcard;
bool has_port_wildcard;
bool has_id_wildcards;
char *updown;
u_int16_t host_port; /* host order */
u_int16_t port; /* host order */
u_int8_t protocol;
cert_t cert; /* end certificate */
chunk_t ca; /* CA distinguished name */
struct ietfAttrList *groups;/* access control groups */
smartcard_t *sc; /* smartcard reader and key info */
#ifdef VIRTUAL_IP
struct virtual_t *virt;
#endif
bool modecfg; /* this end: request local address from server */
/* that end: give local addresses to clients */
bool hostaccess; /* allow access to host via iptables INPUT/OUTPUT */
/* rules if client behind host is a subnet */
certpolicy_t sendcert; /* whether or not to send the certificate */
};
struct spd_route {
struct spd_route *next;
struct end this;
struct end that;
so_serial_t eroute_owner;
enum routing_t routing; /* level of routing in place */
uint32_t reqid;
};
struct connection {
char *name;
lset_t policy;
time_t sa_ike_life_seconds;
time_t sa_ipsec_life_seconds;
time_t sa_rekey_margin;
unsigned long sa_rekey_fuzz;
unsigned long sa_keying_tries;
/* RFC 3706 DPD */
time_t dpd_delay;
time_t dpd_timeout;
dpd_action_t dpd_action;
char *log_file_name; /* name of log file */
FILE *log_file; /* possibly open FILE */
CIRCLEQ_ENTRY(connection) log_link; /* linked list of open conns */
bool log_file_err; /* only bitch once */
struct spd_route spd;
/* internal fields: */
unsigned long instance_serial;
policy_prio_t prio;
bool instance_initiation_ok; /* this is an instance of a policy that mandates initiate */
enum connection_kind kind;
const struct iface *interface; /* filled in iff oriented */
so_serial_t /* state object serial number */
newest_isakmp_sa,
newest_ipsec_sa;
#ifdef DEBUG
lset_t extra_debugging;
#endif
/* note: if the client is the gateway, the following must be equal */
sa_family_t addr_family; /* between gateways */
sa_family_t tunnel_addr_family; /* between clients */
struct connection *policy_next; /* if multiple policies,
next one to apply */
struct gw_info *gw_info;
struct alg_info_esp *alg_info_esp;
struct alg_info_ike *alg_info_ike;
struct host_pair *host_pair;
struct connection *hp_next; /* host pair list link */
struct connection *ac_next; /* all connections list link */
generalName_t *requested_ca; /* collected certificate requests */
bool got_certrequest;
};
#define oriented(c) ((c).interface != NULL)
extern bool orient(struct connection *c);
extern bool same_peer_ids(const struct connection *c
, const struct connection *d, const struct id *his_id);
/* Format the topology of a connection end, leaving out defaults.
* Largest left end looks like: client === host : port [ host_id ] --- hop
* Note: if that==NULL, skip nexthop
*/
#define END_BUF (SUBNETTOT_BUF + ADDRTOT_BUF + IDTOA_BUF + ADDRTOT_BUF + 10)
extern size_t format_end(char *buf, size_t buf_len
, const struct end *this, const struct end *that
, bool is_left, lset_t policy);
extern void add_connection(const whack_message_t *wm);
extern void initiate_connection(const char *name, int whackfd);
extern void initiate_opportunistic(const ip_address *our_client
, const ip_address *peer_client, int transport_proto, bool held, int whackfd);
extern void terminate_connection(const char *nm);
extern void release_connection(struct connection *c, bool relations);
extern void delete_connection(struct connection *c, bool relations);
extern void delete_connections_by_name(const char *name, bool strict);
extern void delete_every_connection(void);
extern char *add_group_instance(struct connection *group, const ip_subnet *target);
extern void remove_group_instance(const struct connection *group, const char *name);
extern void release_dead_interfaces(void);
extern void check_orientations(void);
extern struct connection *route_owner(struct connection *c
, struct spd_route **srp
, struct connection **erop
, struct spd_route **esrp);
extern struct connection *shunt_owner(const ip_subnet *ours
, const ip_subnet *his);
extern bool uniqueIDs; /* --uniqueids? */
extern void ISAKMP_SA_established(struct connection *c, so_serial_t serial);
#define his_id_was_instantiated(c) ((c)->kind == CK_INSTANCE \
&& (id_is_ipaddr(&(c)->spd.that.id)? \
sameaddr(&(c)->spd.that.id.ip_addr, &(c)->spd.that.host_addr) : TRUE))
struct state; /* forward declaration of tag (defined in state.h) */
extern struct connection
*con_by_name(const char *nm, bool strict),
*find_host_connection(const ip_address *me, u_int16_t my_port
, const ip_address *him, u_int16_t his_port, lset_t policy),
*refine_host_connection(const struct state *st, const struct id *id
, chunk_t peer_ca),
*find_client_connection(struct connection *c
, const ip_subnet *our_net
, const ip_subnet *peer_net
, const u_int8_t our_protocol
, const u_int16_t out_port
, const u_int8_t peer_protocol
, const u_int16_t peer_port),
*find_connection_by_reqid(uint32_t reqid);
extern struct connection *
find_connection_for_clients(struct spd_route **srp
, const ip_address *our_client
, const ip_address *peer_client
, int transport_proto);
extern chunk_t get_peer_ca_and_groups(struct connection *c
, const ietfAttrList_t **peer_list);
/* instantiating routines
* Note: connection_discard() is in state.h because all its work
* is looking through state objects.
*/
struct gw_info; /* forward declaration of tag (defined in dnskey.h) */
struct alg_info; /* forward declaration of tag (defined in alg_info.h) */
extern struct connection *rw_instantiate(struct connection *c
, const ip_address *him
#ifdef NAT_TRAVERSAL
, u_int16_t his_port
#endif
#ifdef VIRTUAL_IP
, const ip_subnet *his_net
#endif
, const struct id *his_id);
extern struct connection *oppo_instantiate(struct connection *c
, const ip_address *him
, const struct id *his_id
, struct gw_info *gw
, const ip_address *our_client
, const ip_address *peer_client);
extern struct connection
*build_outgoing_opportunistic_connection(struct gw_info *gw
, const ip_address *our_client
, const ip_address *peer_client);
/* worst case: "[" serial "] " myclient "=== ..." peer "===" hisclient '\0' */
#define CONN_INST_BUF \
(2 + 10 + 1 + SUBNETTOT_BUF + 7 + ADDRTOT_BUF + 3 + SUBNETTOT_BUF + 1)
extern void fmt_conn_instance(const struct connection *c
, char buf[CONN_INST_BUF]);
/* operations on "pending", the structure representing Quick Mode
* negotiations delayed until a Keying Channel has been negotiated.
*/
struct pending; /* forward declaration (opaque outside connections.c) */
extern void add_pending(int whack_sock
, struct state *isakmp_sa
, struct connection *c
, lset_t policy
, unsigned long try
, so_serial_t replacing);
extern void release_pending_whacks(struct state *st, err_t story);
extern void unpend(struct state *st);
extern void update_pending(struct state *os, struct state *ns);
extern void flush_pending_by_state(struct state *st);
extern void show_pending_phase2(const struct host_pair *hp, const struct state *st);
extern void connection_discard(struct connection *c);
/* A template connection's eroute can be eclipsed by
* either a %hold or an eroute for an instance iff
* the template is a /32 -> /32. This requires some special casing.
*/
#define eclipsable(sr) (subnetishost(&(sr)->this.client) && subnetishost(&(sr)->that.client))
extern long eclipse_count;
extern struct connection *eclipsed(struct connection *c, struct spd_route **);
/* print connection status */
extern void show_connections_status(bool all, const char *name);
extern int connection_compare(const struct connection *ca
, const struct connection *cb);
#ifdef NAT_TRAVERSAL
void
update_host_pair(const char *why, struct connection *c,
const ip_address *myaddr, u_int16_t myport ,
const ip_address *hisaddr, u_int16_t hisport);
#endif /* NAT_TRAVERSAL */
#endif /* _CONNECTIONS_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+67
View File
@@ -0,0 +1,67 @@
/* cookie generation/verification routines.
* Copyright (C) 1997 Angelos D. Keromytis.
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
*
* 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: cookie.c,v 1.2 2005/08/17 16:38:20 as Exp $
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "sha1.h"
#include "rnd.h"
#include "cookie.h"
const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */
/* Generate a cookie.
* First argument is true if we're to create an Initiator cookie.
* Length SHOULD be a multiple of sizeof(u_int32_t).
*/
void
get_cookie(bool initiator, u_int8_t *cookie, int length, const ip_address *addr)
{
u_char buffer[SHA1_DIGEST_SIZE];
SHA1_CTX ctx;
do {
if (initiator)
{
get_rnd_bytes(cookie, length);
}
else /* Responder cookie */
{
/* This looks as good as any way */
size_t addr_length;
static u_int32_t counter = 0;
unsigned char addr_buff[
sizeof(union {struct in_addr A; struct in6_addr B;})];
addr_length = addrbytesof(addr, addr_buff, sizeof(addr_buff));
SHA1Init(&ctx);
SHA1Update(&ctx, addr_buff, addr_length);
SHA1Update(&ctx, secret_of_the_day, sizeof(secret_of_the_day));
counter++;
SHA1Update(&ctx, (const void *) &counter, sizeof(counter));
SHA1Final(buffer, &ctx);
memcpy(cookie, buffer, length);
}
} while (is_zero_cookie(cookie)); /* probably never loops */
}
+24
View File
@@ -0,0 +1,24 @@
/* cookie generation/verification routines.
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
*
* 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: cookie.h,v 1.1 2004/03/15 20:35:28 as Exp $
*/
#include <freeswan.h>
extern const u_char zero_cookie[COOKIE_SIZE]; /* guaranteed 0 */
extern void get_cookie(bool initiator, u_int8_t *cookie, int length
, const ip_address *addr);
#define is_zero_cookie(cookie) all_zero((cookie), COOKIE_SIZE)
+763
View File
@@ -0,0 +1,763 @@
/* Support of X.509 certificate revocation lists (CRLs)
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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: crl.c,v 1.12 2005/12/06 22:49:57 as Exp $
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <time.h>
#include <sys/types.h>
#include <freeswan.h>
#include <freeswan/ipsec_policy.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "asn1.h"
#include "oid.h"
#include "x509.h"
#include "crl.h"
#include "ca.h"
#include "certs.h"
#include "keys.h"
#include "whack.h"
#include "fetch.h"
#include "sha1.h"
/* chained lists of X.509 crls */
static x509crl_t *x509crls = NULL;
/* ASN.1 definition of an X.509 certificate list */
static const asn1Object_t crlObjects[] = {
{ 0, "certificateList", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
{ 1, "tbsCertList", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
{ 2, "version", ASN1_INTEGER, ASN1_OPT |
ASN1_BODY }, /* 2 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 3 */
{ 2, "signature", ASN1_EOC, ASN1_RAW }, /* 4 */
{ 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 5 */
{ 2, "thisUpdate", ASN1_EOC, ASN1_RAW }, /* 6 */
{ 2, "nextUpdate", ASN1_EOC, ASN1_RAW }, /* 7 */
{ 2, "revokedCertificates", ASN1_SEQUENCE, ASN1_OPT |
ASN1_LOOP }, /* 8 */
{ 3, "certList", ASN1_SEQUENCE, ASN1_NONE }, /* 9 */
{ 4, "userCertificate", ASN1_INTEGER, ASN1_BODY }, /* 10 */
{ 4, "revocationDate", ASN1_EOC, ASN1_RAW }, /* 11 */
{ 4, "crlEntryExtensions", ASN1_SEQUENCE, ASN1_OPT |
ASN1_LOOP }, /* 12 */
{ 5, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 13 */
{ 6, "extnID", ASN1_OID, ASN1_BODY }, /* 14 */
{ 6, "critical", ASN1_BOOLEAN, ASN1_DEF |
ASN1_BODY }, /* 15 */
{ 6, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 16 */
{ 4, "end opt or loop", ASN1_EOC, ASN1_END }, /* 17 */
{ 2, "end opt or loop", ASN1_EOC, ASN1_END }, /* 18 */
{ 2, "optional extensions", ASN1_CONTEXT_C_0, ASN1_OPT }, /* 19 */
{ 3, "crlExtensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 20 */
{ 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 21 */
{ 5, "extnID", ASN1_OID, ASN1_BODY }, /* 22 */
{ 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
ASN1_BODY }, /* 23 */
{ 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 24 */
{ 3, "end loop", ASN1_EOC, ASN1_END }, /* 25 */
{ 2, "end opt", ASN1_EOC, ASN1_END }, /* 26 */
{ 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 27 */
{ 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY } /* 28 */
};
#define CRL_OBJ_CERTIFICATE_LIST 0
#define CRL_OBJ_TBS_CERT_LIST 1
#define CRL_OBJ_VERSION 2
#define CRL_OBJ_SIG_ALG 4
#define CRL_OBJ_ISSUER 5
#define CRL_OBJ_THIS_UPDATE 6
#define CRL_OBJ_NEXT_UPDATE 7
#define CRL_OBJ_USER_CERTIFICATE 10
#define CRL_OBJ_REVOCATION_DATE 11
#define CRL_OBJ_CRL_ENTRY_EXTN_ID 14
#define CRL_OBJ_CRL_ENTRY_CRITICAL 15
#define CRL_OBJ_CRL_ENTRY_EXTN_VALUE 16
#define CRL_OBJ_EXTN_ID 22
#define CRL_OBJ_CRITICAL 23
#define CRL_OBJ_EXTN_VALUE 24
#define CRL_OBJ_ALGORITHM 27
#define CRL_OBJ_SIGNATURE 28
#define CRL_OBJ_ROOF 29
const x509crl_t empty_x509crl = {
NULL , /* *next */
UNDEFINED_TIME, /* installed */
NULL , /* distributionPoints */
{ NULL, 0 } , /* certificateList */
{ NULL, 0 } , /* tbsCertList */
1 , /* version */
OID_UNKNOWN , /* sigAlg */
{ NULL, 0 } , /* issuer */
UNDEFINED_TIME, /* thisUpdate */
UNDEFINED_TIME, /* nextUpdate */
NULL , /* revokedCertificates */
/* crlExtensions */
/* extension */
/* extnID */
/* critical */
/* extnValue */
{ NULL, 0 } , /* authKeyID */
{ NULL, 0 } , /* authKeySerialNumber */
OID_UNKNOWN , /* algorithm */
{ NULL, 0 } /* signature */
};
/*
* get the X.509 CRL with a given issuer
*/
static x509crl_t*
get_x509crl(chunk_t issuer, chunk_t serial, chunk_t keyid)
{
x509crl_t *crl = x509crls;
x509crl_t *prev_crl = NULL;
while (crl != NULL)
{
if ((keyid.ptr != NULL && crl->authKeyID.ptr != NULL)
? same_keyid(keyid, crl->authKeyID)
: (same_dn(crl->issuer, issuer) && same_serial(serial, crl->authKeySerialNumber)))
{
if (crl != x509crls)
{
/* bring the CRL up front */
prev_crl->next = crl->next;
crl->next = x509crls;
x509crls = crl;
}
return crl;
}
prev_crl = crl;
crl = crl->next;
}
return NULL;
}
/*
* free the dynamic memory used to store revoked certificates
*/
static void
free_revoked_certs(revokedCert_t* revokedCerts)
{
while (revokedCerts != NULL)
{
revokedCert_t * revokedCert = revokedCerts;
revokedCerts = revokedCert->next;
pfree(revokedCert);
}
}
/*
* free the dynamic memory used to store CRLs
*/
void
free_crl(x509crl_t *crl)
{
free_revoked_certs(crl->revokedCertificates);
free_generalNames(crl->distributionPoints, TRUE);
pfree(crl->certificateList.ptr);
pfree(crl);
}
static void
free_first_crl(void)
{
x509crl_t *crl = x509crls;
x509crls = crl->next;
free_crl(crl);
}
void
free_crls(void)
{
lock_crl_list("free_crls");
while (x509crls != NULL)
free_first_crl();
unlock_crl_list("free_crls");
}
/*
* Insert X.509 CRL into chained list
*/
bool
insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl)
{
x509crl_t *crl = alloc_thing(x509crl_t, "x509crl");
*crl = empty_x509crl;
if (parse_x509crl(blob, 0, crl))
{
x509cert_t *issuer_cert;
x509crl_t *oldcrl;
bool valid_sig;
generalName_t *gn;
/* add distribution point */
gn = alloc_thing(generalName_t, "generalName");
gn->kind = GN_URI;
gn->name = crl_uri;
gn->next = crl->distributionPoints;
crl->distributionPoints = gn;
lock_authcert_list("insert_crl");
/* get the issuer cacert */
issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber,
crl->authKeyID, AUTH_CA);
if (issuer_cert == NULL)
{
plog("crl issuer cacert not found");
free_crl(crl);
unlock_authcert_list("insert_crl");
return FALSE;
}
DBG(DBG_CONTROL,
DBG_log("crl issuer cacert found")
)
/* check the issuer's signature of the crl */
valid_sig = check_signature(crl->tbsCertList, crl->signature
, crl->algorithm, crl->algorithm, issuer_cert);
unlock_authcert_list("insert_crl");
if (!valid_sig)
{
free_crl(crl);
return FALSE;
}
DBG(DBG_CONTROL,
DBG_log("crl signature is valid")
)
lock_crl_list("insert_crl");
oldcrl = get_x509crl(crl->issuer, crl->authKeySerialNumber
, crl->authKeyID);
if (oldcrl != NULL)
{
if (crl->thisUpdate > oldcrl->thisUpdate)
{
/* keep any known CRL distribution points */
add_distribution_points(oldcrl->distributionPoints
, &crl->distributionPoints);
/* now delete the old CRL */
free_first_crl();
DBG(DBG_CONTROL,
DBG_log("thisUpdate is newer - existing crl deleted")
)
}
else
{
unlock_crl_list("insert_crls");
DBG(DBG_CONTROL,
DBG_log("thisUpdate is not newer - existing crl not replaced");
)
free_crl(crl);
return oldcrl->nextUpdate - time(NULL) > 2*crl_check_interval;
}
}
/* insert new CRL */
crl->next = x509crls;
x509crls = crl;
unlock_crl_list("insert_crl");
/* If crl caching is enabled then the crl is saved locally.
* Only http or ldap URIs are cached but not local file URIs.
* The issuer's subjectKeyID is used as a unique filename
*/
if (cache_crl && strncasecmp(crl_uri.ptr, "file", 4) != 0)
{
char path[BUF_LEN];
char buf[BUF_LEN];
char digest_buf[SHA1_DIGEST_SIZE];
chunk_t subjectKeyID = { digest_buf, SHA1_DIGEST_SIZE };
if (issuer_cert->subjectKeyID.ptr == NULL)
compute_subjectKeyID(issuer_cert, subjectKeyID);
else
subjectKeyID = issuer_cert->subjectKeyID;
datatot(subjectKeyID.ptr, subjectKeyID.len, 16, buf, BUF_LEN);
snprintf(path, BUF_LEN, "%s/%s.crl", CRL_PATH, buf);
write_chunk(path, "crl", crl->certificateList, 0022, TRUE);
}
/* is the fetched crl valid? */
return crl->nextUpdate - time(NULL) > 2*crl_check_interval;
}
else
{
plog(" error in X.509 crl");
free_crl(crl);
return FALSE;
}
}
/*
* Loads CRLs
*/
void
load_crls(void)
{
struct dirent **filelist;
u_char buf[BUF_LEN];
u_char *save_dir;
int n;
/* change directory to specified path */
save_dir = getcwd(buf, BUF_LEN);
if (chdir(CRL_PATH))
{
plog("Could not change to directory '%s'", CRL_PATH);
}
else
{
plog("Changing to directory '%s'", CRL_PATH);
n = scandir(CRL_PATH, &filelist, file_select, alphasort);
if (n < 0)
plog(" scandir() error");
else
{
while (n--)
{
bool pgp = FALSE;
chunk_t blob = empty_chunk;
char *filename = filelist[n]->d_name;
if (load_coded_file(filename, NULL, "crl", &blob, &pgp))
{
chunk_t crl_uri;
crl_uri.len = 7 + sizeof(CRL_PATH) + strlen(filename);
crl_uri.ptr = alloc_bytes(crl_uri.len + 1, "crl uri");
/* build CRL file URI */
snprintf(crl_uri.ptr, crl_uri.len + 1, "file://%s/%s"
, CRL_PATH, filename);
insert_crl(blob, crl_uri, FALSE);
}
free(filelist[n]);
}
free(filelist);
}
}
/* restore directory path */
chdir(save_dir);
}
/*
* Parses a CRL revocation reason code
*/
static crl_reason_t
parse_crl_reasonCode(chunk_t object)
{
crl_reason_t reason = REASON_UNSPECIFIED;
if (*object.ptr == ASN1_ENUMERATED
&& asn1_length(&object) == 1)
{
reason = *object.ptr;
}
DBG(DBG_PARSING,
DBG_log(" '%s'", enum_name(&crl_reason_names, reason))
)
return reason;
}
/*
* Parses an X.509 CRL
*/
bool
parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl)
{
u_char buf[BUF_LEN];
asn1_ctx_t ctx;
bool critical;
chunk_t extnID;
chunk_t userCertificate;
chunk_t object;
u_int level;
int objectID = 0;
asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
while (objectID < CRL_OBJ_ROOF)
{
if (!extract_object(crlObjects, &objectID, &object, &level, &ctx))
return FALSE;
/* those objects which will parsed further need the next higher level */
level++;
switch (objectID) {
case CRL_OBJ_CERTIFICATE_LIST:
crl->certificateList = object;
break;
case CRL_OBJ_TBS_CERT_LIST:
crl->tbsCertList = object;
break;
case CRL_OBJ_VERSION:
crl->version = (object.len) ? (1+(u_int)*object.ptr) : 1;
DBG(DBG_PARSING,
DBG_log(" v%d", crl->version);
)
break;
case CRL_OBJ_SIG_ALG:
crl->sigAlg = parse_algorithmIdentifier(object, level, NULL);
break;
case CRL_OBJ_ISSUER:
crl->issuer = object;
DBG(DBG_PARSING,
dntoa(buf, BUF_LEN, object);
DBG_log(" '%s'",buf)
)
break;
case CRL_OBJ_THIS_UPDATE:
crl->thisUpdate = parse_time(object, level);
break;
case CRL_OBJ_NEXT_UPDATE:
crl->nextUpdate = parse_time(object, level);
break;
case CRL_OBJ_USER_CERTIFICATE:
userCertificate = object;
break;
case CRL_OBJ_REVOCATION_DATE:
{
/* put all the serial numbers and the revocation date in a chained list
with revocedCertificates pointing to the first revoked certificate */
revokedCert_t *revokedCert = alloc_thing(revokedCert_t, "revokedCert");
revokedCert->userCertificate = userCertificate;
revokedCert->revocationDate = parse_time(object, level);
revokedCert->revocationReason = REASON_UNSPECIFIED;
revokedCert->next = crl->revokedCertificates;
crl->revokedCertificates = revokedCert;
}
break;
case CRL_OBJ_CRL_ENTRY_EXTN_ID:
case CRL_OBJ_EXTN_ID:
extnID = object;
break;
case CRL_OBJ_CRL_ENTRY_CRITICAL:
case CRL_OBJ_CRITICAL:
critical = object.len && *object.ptr;
DBG(DBG_PARSING,
DBG_log(" %s",(critical)?"TRUE":"FALSE");
)
break;
case CRL_OBJ_CRL_ENTRY_EXTN_VALUE:
case CRL_OBJ_EXTN_VALUE:
{
u_int extn_oid = known_oid(extnID);
if (extn_oid == OID_CRL_REASON_CODE)
{
crl->revokedCertificates->revocationReason =
parse_crl_reasonCode(object);
}
else if (extn_oid == OID_AUTHORITY_KEY_ID)
{
parse_authorityKeyIdentifier(object, level
, &crl->authKeyID, &crl->authKeySerialNumber);
}
}
break;
case CRL_OBJ_ALGORITHM:
crl->algorithm = parse_algorithmIdentifier(object, level, NULL);
break;
case CRL_OBJ_SIGNATURE:
crl->signature = object;
break;
default:
break;
}
objectID++;
}
time(&crl->installed);
return TRUE;
}
/* Checks if the current certificate is revoked. It goes through the
* list of revoked certificates of the corresponding crl. Either the
* status CERT_GOOD or CERT_REVOKED is returned
*/
static cert_status_t
check_revocation(const x509crl_t *crl, chunk_t serial
, time_t *revocationDate, crl_reason_t * revocationReason)
{
revokedCert_t *revokedCert = crl->revokedCertificates;
*revocationDate = UNDEFINED_TIME;
*revocationReason = REASON_UNSPECIFIED;
DBG(DBG_CONTROL,
DBG_dump_chunk("serial number:", serial)
)
while(revokedCert != NULL)
{
/* compare serial numbers */
if (revokedCert->userCertificate.len == serial.len &&
memcmp(revokedCert->userCertificate.ptr, serial.ptr, serial.len) == 0)
{
*revocationDate = revokedCert->revocationDate;
*revocationReason = revokedCert->revocationReason;
return CERT_REVOKED;
}
revokedCert = revokedCert->next;
}
return CERT_GOOD;
}
/*
* check if any crls are about to expire
*/
void
check_crls(void)
{
x509crl_t *crl;
lock_crl_list("check_crls");
crl = x509crls;
while (crl != NULL)
{
time_t time_left = crl->nextUpdate - time(NULL);
u_char buf[BUF_LEN];
DBG(DBG_CONTROL,
dntoa(buf, BUF_LEN, crl->issuer);
DBG_log("issuer: '%s'",buf);
if (crl->authKeyID.ptr != NULL)
{
datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
, buf, BUF_LEN);
DBG_log("authkey: %s", buf);
}
DBG_log("%ld seconds left", time_left)
)
if (time_left < 2*crl_check_interval)
{
fetch_req_t *req = build_crl_fetch_request(crl->issuer
, crl->authKeySerialNumber
, crl->authKeyID, crl->distributionPoints);
add_crl_fetch_request(req);
}
crl = crl->next;
}
unlock_crl_list("check_crls");
}
/*
* verify if a cert hasn't been revoked by a crl
*/
cert_status_t
verify_by_crl(const x509cert_t *cert, time_t *until, time_t *revocationDate
, crl_reason_t *revocationReason)
{
x509crl_t *crl;
ca_info_t *ca = get_ca_info(cert->issuer, cert->authKeySerialNumber
, cert->authKeyID);
generalName_t *crluri = (ca == NULL)? NULL : ca->crluri;
*revocationDate = UNDEFINED_TIME;
*revocationReason = REASON_UNSPECIFIED;
lock_crl_list("verify_by_crl");
crl = get_x509crl(cert->issuer, cert->authKeySerialNumber, cert->authKeyID);
if (crl == NULL)
{
unlock_crl_list("verify_by_crl");
plog("crl not found");
if (cert->crlDistributionPoints != NULL)
{
fetch_req_t *req = build_crl_fetch_request(cert->issuer
, cert->authKeySerialNumber
, cert->authKeyID, cert->crlDistributionPoints);
add_crl_fetch_request(req);
}
if (crluri != NULL)
{
fetch_req_t *req = build_crl_fetch_request(cert->issuer
, cert->authKeySerialNumber
, cert->authKeyID, crluri);
add_crl_fetch_request(req);
}
if (cert->crlDistributionPoints != 0 || crluri != NULL)
{
wake_fetch_thread("verify_by_crl");
return CERT_UNKNOWN;
}
else
return CERT_UNDEFINED;
}
else
{
x509cert_t *issuer_cert;
bool valid;
DBG(DBG_CONTROL,
DBG_log("crl found")
)
add_distribution_points(cert->crlDistributionPoints
, &crl->distributionPoints);
add_distribution_points(crluri
, &crl->distributionPoints);
lock_authcert_list("verify_by_crl");
issuer_cert = get_authcert(crl->issuer, crl->authKeySerialNumber
, crl->authKeyID, AUTH_CA);
valid = check_signature(crl->tbsCertList, crl->signature
, crl->algorithm, crl->algorithm, issuer_cert);
unlock_authcert_list("verify_by_crl");
if (valid)
{
cert_status_t status;
DBG(DBG_CONTROL,
DBG_log("crl signature is valid")
)
/* return the expiration date */
*until = crl->nextUpdate;
/* has the certificate been revoked? */
status = check_revocation(crl, cert->serialNumber, revocationDate
, revocationReason);
if (*until < time(NULL))
{
fetch_req_t *req;
plog("crl update is overdue since %s"
, timetoa(until, TRUE));
/* try to fetch a crl update */
req = build_crl_fetch_request(crl->issuer
, crl->authKeySerialNumber
, crl->authKeyID, crl->distributionPoints);
unlock_crl_list("verify_by_crl");
add_crl_fetch_request(req);
wake_fetch_thread("verify_by_crl");
}
else
{
unlock_crl_list("verify_by_crl");
DBG(DBG_CONTROL,
DBG_log("crl is valid")
)
}
return status;
}
else
{
unlock_crl_list("verify_by_crl");
plog("crl signature is invalid");
return CERT_UNKNOWN;
}
}
}
/*
* list all X.509 crls in the chained list
*/
void
list_crls(bool utc, bool strict)
{
x509crl_t *crl;
lock_crl_list("list_crls");
crl = x509crls;
if (crl != NULL)
{
whack_log(RC_COMMENT, " ");
whack_log(RC_COMMENT, "List of X.509 CRLs:");
whack_log(RC_COMMENT, " ");
}
while (crl != NULL)
{
u_char buf[BUF_LEN];
u_int revoked = 0;
revokedCert_t *revokedCert = crl->revokedCertificates;
/* count number of revoked certificates in CRL */
while (revokedCert != NULL)
{
revoked++;
revokedCert = revokedCert->next;
}
whack_log(RC_COMMENT, "%s, revoked certs: %d",
timetoa(&crl->installed, utc), revoked);
dntoa(buf, BUF_LEN, crl->issuer);
whack_log(RC_COMMENT, " issuer: '%s'", buf);
list_distribution_points(crl->distributionPoints);
whack_log(RC_COMMENT, " updates: this %s",
timetoa(&crl->thisUpdate, utc));
whack_log(RC_COMMENT, " next %s %s",
timetoa(&crl->nextUpdate, utc),
check_expiry(crl->nextUpdate, CRL_WARNING_INTERVAL, strict));
if (crl->authKeyID.ptr != NULL)
{
datatot(crl->authKeyID.ptr, crl->authKeyID.len, ':'
, buf, BUF_LEN);
whack_log(RC_COMMENT, " authkey: %s", buf);
}
if (crl->authKeySerialNumber.ptr != NULL)
{
datatot(crl->authKeySerialNumber.ptr, crl->authKeySerialNumber.len, ':'
, buf, BUF_LEN);
whack_log(RC_COMMENT, " aserial: %s", buf);
}
crl = crl->next;
}
unlock_crl_list("list_crls");
}
+87
View File
@@ -0,0 +1,87 @@
/* Support of X.509 certificate revocation lists (CRLs)
* Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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: crl.h,v 1.4 2005/07/18 19:36:22 as Exp $
*/
#include "constants.h"
/* access structure for a revoked serial number */
typedef struct revokedCert revokedCert_t;
struct revokedCert{
revokedCert_t *next;
chunk_t userCertificate;
time_t revocationDate;
crl_reason_t revocationReason;
};
/* storage structure for an X.509 CRL */
typedef struct x509crl x509crl_t;
struct x509crl {
x509crl_t *next;
time_t installed;
generalName_t *distributionPoints;
chunk_t certificateList;
chunk_t tbsCertList;
u_int version;
/* signature */
int sigAlg;
chunk_t issuer;
time_t thisUpdate;
time_t nextUpdate;
revokedCert_t *revokedCertificates;
/* v2 extensions */
/* crlExtensions */
/* extension */
/* extnID */
/* critical */
/* extnValue */
chunk_t authKeyID;
chunk_t authKeySerialNumber;
/* signatureAlgorithm */
int algorithm;
chunk_t signature;
};
/* apply a strict CRL policy
* flag set in plutomain.c and used in ipsec_doi.c and rcv_whack.c
*/
extern bool strict_crl_policy;
/*
* cache the retrieved CRLs by storing them locally as a file
*/
extern bool cache_crls;
/*
* check periodically for expired crls
*/
extern long crl_check_interval;
/* used for initialization */
extern const x509crl_t empty_x509crl;
extern bool parse_x509crl(chunk_t blob, u_int level0, x509crl_t *crl);
extern void load_crls(void);
extern void check_crls(void);
extern bool insert_crl(chunk_t blob, chunk_t crl_uri, bool cache_crl);
extern cert_status_t verify_by_crl(const x509cert_t *cert, time_t *until
, time_t *revocationDate, crl_reason_t *revocationReason);
extern void list_crls(bool utc, bool strict);
extern void free_crls(void);
extern void free_crl(x509crl_t *crl);
+261
View File
@@ -0,0 +1,261 @@
/* crypto interfaces
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: crypto.c,v 1.5 2005/12/06 22:51:34 as Exp $
*/
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <sys/types.h>
#include <freeswan.h>
#define HEADER_DES_LOCL_H /* stupid trick to force prototype decl in <des.h> */
#include <crypto/des.h>
#include <errno.h>
#include "constants.h"
#include "defs.h"
#include "state.h"
#include "log.h"
#include "md5.h"
#include "sha1.h"
#include "crypto.h" /* requires sha1.h and md5.h */
#include "alg_info.h"
#include "ike_alg.h"
/* moduli and generator. */
static MP_INT
modp1024_modulus,
modp1536_modulus,
modp2048_modulus,
modp3072_modulus,
modp4096_modulus,
modp6144_modulus,
modp8192_modulus;
MP_INT groupgenerator; /* MODP group generator (2) */
static void do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc);
static struct encrypt_desc crypto_encryptor_3des =
{
algo_type: IKE_ALG_ENCRYPT,
algo_id: OAKLEY_3DES_CBC,
algo_next: NULL,
enc_ctxsize: sizeof(des_key_schedule) * 3,
enc_blocksize: DES_CBC_BLOCK_SIZE,
keydeflen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
keyminlen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
keymaxlen: DES_CBC_BLOCK_SIZE * 3 * BITS_PER_BYTE,
do_crypt: do_3des,
};
static struct hash_desc crypto_hasher_md5 =
{
algo_type: IKE_ALG_HASH,
algo_id: OAKLEY_MD5,
algo_next: NULL,
hash_ctx_size: sizeof(MD5_CTX),
hash_digest_size: MD5_DIGEST_SIZE,
hash_init: (void (*)(void *)) MD5Init,
hash_update: (void (*)(void *, const u_int8_t *, size_t)) MD5Update,
hash_final: (void (*)(u_char *, void *)) MD5Final,
};
static struct hash_desc crypto_hasher_sha1 =
{
algo_type: IKE_ALG_HASH,
algo_id: OAKLEY_SHA,
algo_next: NULL,
hash_ctx_size: sizeof(SHA1_CTX),
hash_digest_size: SHA1_DIGEST_SIZE,
hash_init: (void (*)(void *)) SHA1Init,
hash_update: (void (*)(void *, const u_int8_t *, size_t)) SHA1Update,
hash_final: (void (*)(u_char *, void *)) SHA1Final,
};
void
init_crypto(void)
{
if (mpz_init_set_str(&groupgenerator, MODP_GENERATOR, 10) != 0
|| mpz_init_set_str(&modp1024_modulus, MODP1024_MODULUS, 16) != 0
|| mpz_init_set_str(&modp1536_modulus, MODP1536_MODULUS, 16) != 0
|| mpz_init_set_str(&modp2048_modulus, MODP2048_MODULUS, 16) != 0
|| mpz_init_set_str(&modp3072_modulus, MODP3072_MODULUS, 16) != 0
|| mpz_init_set_str(&modp4096_modulus, MODP4096_MODULUS, 16) != 0
|| mpz_init_set_str(&modp6144_modulus, MODP6144_MODULUS, 16) != 0
|| mpz_init_set_str(&modp8192_modulus, MODP8192_MODULUS, 16) != 0)
exit_log("mpz_init_set_str() failed in init_crypto()");
ike_alg_add((struct ike_alg *) &crypto_encryptor_3des);
ike_alg_add((struct ike_alg *) &crypto_hasher_sha1);
ike_alg_add((struct ike_alg *) &crypto_hasher_md5);
ike_alg_init();
}
/* Oakley group description
*
* See RFC2409 "The Internet key exchange (IKE)" 6.
*/
const struct oakley_group_desc unset_group = {0, NULL, 0}; /* magic signifier */
const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE] = {
# define BYTES(bits) (((bits) + BITS_PER_BYTE - 1) / BITS_PER_BYTE)
{ OAKLEY_GROUP_MODP1024, &modp1024_modulus, BYTES(1024) },
{ OAKLEY_GROUP_MODP1536, &modp1536_modulus, BYTES(1536) },
{ OAKLEY_GROUP_MODP2048, &modp2048_modulus, BYTES(2048) },
{ OAKLEY_GROUP_MODP3072, &modp3072_modulus, BYTES(3072) },
{ OAKLEY_GROUP_MODP4096, &modp4096_modulus, BYTES(4096) },
{ OAKLEY_GROUP_MODP6144, &modp6144_modulus, BYTES(6144) },
{ OAKLEY_GROUP_MODP8192, &modp8192_modulus, BYTES(8192) },
# undef BYTES
};
const struct oakley_group_desc *
lookup_group(u_int16_t group)
{
int i;
for (i = 0; i != elemsof(oakley_group); i++)
if (group == oakley_group[i].group)
return &oakley_group[i];
return NULL;
}
/* Encryption Routines
*
* Each uses and updates the state object's st_new_iv.
* This must already be initialized.
*/
/* encrypt or decrypt part of an IKE message using DES
* See RFC 2409 "IKE" Appendix B
*/
static void __attribute__ ((unused))
do_des(bool enc, void *buf, size_t buf_len, struct state *st)
{
des_key_schedule ks;
(void) des_set_key((des_cblock *)st->st_enc_key.ptr, ks);
passert(st->st_new_iv_len >= DES_CBC_BLOCK_SIZE);
st->st_new_iv_len = DES_CBC_BLOCK_SIZE; /* truncate */
des_ncbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len,
ks,
(des_cblock *)st->st_new_iv, enc);
}
/* encrypt or decrypt part of an IKE message using 3DES
* See RFC 2409 "IKE" Appendix B
*/
static void
do_3des(u_int8_t *buf, size_t buf_len, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc)
{
des_key_schedule ks[3];
passert (!key_size || (key_size==(DES_CBC_BLOCK_SIZE * 3)))
(void) des_set_key((des_cblock *)key + 0, ks[0]);
(void) des_set_key((des_cblock *)key + 1, ks[1]);
(void) des_set_key((des_cblock *)key + 2, ks[2]);
des_ede3_cbc_encrypt((des_cblock *)buf, (des_cblock *)buf, buf_len,
ks[0], ks[1], ks[2],
(des_cblock *)iv, enc);
}
/* hash and prf routines */
void
crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st)
{
passert(st->st_new_iv_len >= e->enc_blocksize);
st->st_new_iv_len = e->enc_blocksize; /* truncate */
e->do_crypt(buf, size, st->st_enc_key.ptr, st->st_enc_key.len, st->st_new_iv, enc);
/*
e->set_key(&ctx, st->st_enc_key.ptr, st->st_enc_key.len);
e->cbc_crypt(&ctx, buf, size, st->st_new_iv, enc);
*/
}
/* HMAC package
* rfc2104.txt specifies how HMAC works.
*/
void
hmac_init(struct hmac_ctx *ctx,
const struct hash_desc *h,
const u_char *key, size_t key_len)
{
int k;
ctx->h = h;
ctx->hmac_digest_size = h->hash_digest_size;
/* Prepare the two pads for the HMAC */
memset(ctx->buf1, '\0', HMAC_BUFSIZE);
if (key_len <= HMAC_BUFSIZE)
{
memcpy(ctx->buf1, key, key_len);
}
else
{
h->hash_init(&ctx->hash_ctx);
h->hash_update(&ctx->hash_ctx, key, key_len);
h->hash_final(ctx->buf1, &ctx->hash_ctx);
}
memcpy(ctx->buf2, ctx->buf1, HMAC_BUFSIZE);
for (k = 0; k < HMAC_BUFSIZE; k++)
{
ctx->buf1[k] ^= HMAC_IPAD;
ctx->buf2[k] ^= HMAC_OPAD;
}
hmac_reinit(ctx);
}
void
hmac_reinit(struct hmac_ctx *ctx)
{
ctx->h->hash_init(&ctx->hash_ctx);
ctx->h->hash_update(&ctx->hash_ctx, ctx->buf1, HMAC_BUFSIZE);
}
void
hmac_update(struct hmac_ctx *ctx,
const u_char *data, size_t data_len)
{
ctx->h->hash_update(&ctx->hash_ctx, data, data_len);
}
void
hmac_final(u_char *output, struct hmac_ctx *ctx)
{
const struct hash_desc *h = ctx->h;
h->hash_final(output, &ctx->hash_ctx);
h->hash_init(&ctx->hash_ctx);
h->hash_update(&ctx->hash_ctx, ctx->buf2, HMAC_BUFSIZE);
h->hash_update(&ctx->hash_ctx, output, h->hash_digest_size);
h->hash_final(output, &ctx->hash_ctx);
}
+107
View File
@@ -0,0 +1,107 @@
/* crypto interfaces
* Copyright (C) 1998, 1999 D. Hugh Redelmeier.
*
* 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: crypto.h,v 1.6 2005/04/07 20:13:30 as Exp $
*/
#include <gmp.h> /* GNU MP library */
#include "libsha2/sha2.h"
#include "ike_alg.h"
extern void init_crypto(void);
/* Oakley group descriptions */
extern MP_INT groupgenerator; /* MODP group generator (2) */
struct oakley_group_desc {
u_int16_t group;
MP_INT *modulus;
size_t bytes;
};
extern const struct oakley_group_desc unset_group; /* magic signifier */
extern const struct oakley_group_desc *lookup_group(u_int16_t group);
#define OAKLEY_GROUP_SIZE 7
extern const struct oakley_group_desc oakley_group[OAKLEY_GROUP_SIZE];
/* unification of cryptographic encoding/decoding algorithms
* The IV is taken from and returned to st->st_new_iv.
* This allows the old IV to be retained.
* Use update_iv to commit to the new IV (for example, once a packet has
* been validated).
*/
#define MAX_OAKLEY_KEY_LEN0 (3 * DES_CBC_BLOCK_SIZE)
#define MAX_OAKLEY_KEY_LEN (256/BITS_PER_BYTE)
struct state; /* forward declaration, dammit */
void crypto_cbc_encrypt(const struct encrypt_desc *e, bool enc, u_int8_t *buf, size_t size, struct state *st);
#define update_iv(st) memcpy((st)->st_iv, (st)->st_new_iv \
, (st)->st_iv_len = (st)->st_new_iv_len)
#define set_ph1_iv(st, iv) \
passert((st)->st_ph1_iv_len <= sizeof((st)->st_ph1_iv)); \
memcpy((st)->st_ph1_iv, (iv), (st)->st_ph1_iv_len);
/* unification of cryptographic hashing mechanisms */
#ifndef NO_HASH_CTX
union hash_ctx {
MD5_CTX ctx_md5;
SHA1_CTX ctx_sha1;
sha256_context ctx_sha256;
sha512_context ctx_sha512;
};
/* HMAC package
* Note that hmac_ctx can be (and is) copied since there are
* no persistent pointers into it.
*/
struct hmac_ctx {
const struct hash_desc *h; /* underlying hash function */
size_t hmac_digest_size; /* copy of h->hash_digest_size */
union hash_ctx hash_ctx; /* ctx for hash function */
u_char buf1[HMAC_BUFSIZE], buf2[HMAC_BUFSIZE];
};
extern void hmac_init(
struct hmac_ctx *ctx,
const struct hash_desc *h,
const u_char *key,
size_t key_len);
#define hmac_init_chunk(ctx, h, ch) hmac_init((ctx), (h), (ch).ptr, (ch).len)
extern void hmac_reinit(struct hmac_ctx *ctx); /* saves recreating pads */
extern void hmac_update(
struct hmac_ctx *ctx,
const u_char *data,
size_t data_len);
#define hmac_update_chunk(ctx, ch) hmac_update((ctx), (ch).ptr, (ch).len)
extern void hmac_final(u_char *output, struct hmac_ctx *ctx);
#define hmac_final_chunk(ch, name, ctx) { \
pfreeany((ch).ptr); \
(ch).len = (ctx)->hmac_digest_size; \
(ch).ptr = alloc_bytes((ch).len, name); \
hmac_final((ch).ptr, (ctx)); \
}
#endif
+439
View File
@@ -0,0 +1,439 @@
/* Dynamic db (proposal, transforms, attributes) handling.
* Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
*
* 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: db_ops.c,v 1.4 2005/04/07 20:13:44 as Exp $
*/
/*
* The stratedy is to have (full contained) struct db_prop in db_context
* pointing to ONE dynamically sizable transform vector (trans0).
* Each transform stores attrib. in ONE dyn. sizable attribute vector (attrs0)
* in a "serialized" way (attributes storage is used in linear sequence for
* subsecuent transforms).
*
* Resizing for both trans0 and attrs0 is supported:
* - For trans0: quite simple, just allocate and copy trans. vector content
* also update trans_cur (by offset)
* - For attrs0: after allocating and copying attrs, I must rewrite each
* trans->attrs present in trans0; to achieve this, calculate
* attrs pointer offset (new minus old) and iterate over
* each transform "adding" this difference.
* also update attrs_cur (by offset)
*
* db_context structure:
* +---------------------+
* | prop |
* | .protoid |
* | .trans | --+
* | .trans_cnt | |
* +---------------------+ <-+
* | trans0 | ----> { trans#1 | ... | trans#i | ... }
* +---------------------+ ^
* | trans_cur | ----------------------' current transf.
* +---------------------+
* | attrs0 | ----> { attr#1 | ... | attr#j | ... }
* +---------------------+ ^
* | attrs_cur | ---------------------' current attr.
* +---------------------+
* | max_trans,max_attrs | max_trans/attrs: number of elem. of each vector
* +---------------------+
*
* See testing examples at end for interface usage.
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include <sys/types.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "state.h"
#include "packet.h"
#include "spdb.h"
#include "db_ops.h"
#include "log.h"
#include "whack.h"
#include <assert.h>
#ifndef NO_PLUTO
#else
#define passert(x) assert(x)
extern int debug; /* eg: spi.c */
#define DBG(cond, action) { if (debug) { action ; } }
#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
#define alloc_thing(thing, name) alloc_bytes(sizeof (thing), name)
void * alloc_bytes(size_t size, const char *name) {
void *p=malloc(size);
if (p == NULL)
fprintf(stderr, "unable to malloc %lu bytes for %s",
(unsigned long) size, name);
memset(p, '\0', size);
return p;
}
#define pfreeany(ptr) free(ptr)
#endif
#ifdef NOT_YET
/*
* Allocator cache:
* Because of the single-threaded nature of pluto/spdb.c,
* alloc()/free() is exercised many times with very small
* lifetime objects.
* Just caching last object (currently it will select the
* largest) will avoid this allocation mas^Wperturbations
*
*/
struct db_ops_alloc_cache {
void *ptr;
int size;
};
#endif
#ifndef NO_DB_OPS_STATS
/*
* stats: do account for allocations
* displayed in db_ops_show_status()
*/
struct db_ops_stats {
int st_curr_cnt; /* current number of allocations */
int st_total_cnt; /* total allocations so far */
size_t st_maxsz; /* max. size requested */
};
#define DB_OPS_ZERO { 0, 0, 0};
#define DB_OPS_STATS_DESC "{curr_cnt, total_cnt, maxsz}"
#define DB_OPS_STATS_STR(name) name "={%d,%d,%d} "
#define DB_OPS_STATS_F(st) (st).st_curr_cnt, (st).st_total_cnt, (int)(st).st_maxsz
static struct db_ops_stats db_context_st = DB_OPS_ZERO;
static struct db_ops_stats db_trans_st = DB_OPS_ZERO;
static struct db_ops_stats db_attrs_st = DB_OPS_ZERO;
static __inline__ void * alloc_bytes_st (size_t size, const char *str, struct db_ops_stats *st)
{
void *ptr = alloc_bytes(size, str);
if (ptr) {
st->st_curr_cnt++;
st->st_total_cnt++;
if (size > st->st_maxsz) st->st_maxsz=size;
}
return ptr;
}
#define ALLOC_BYTES_ST(z,s,st) alloc_bytes_st(z, s, &st);
#define PFREE_ST(p,st) do { st.st_curr_cnt--; pfree(p); } while (0);
#else
#define ALLOC_BYTES_ST(z,s,n) alloc_bytes(z, s);
#define PFREE_ST(p,n) pfree(p);
#endif /* NO_DB_OPS_STATS */
/* Initialize db object
* max_trans and max_attrs can be 0, will be dynamically expanded
* as a result of "add" operations
*/
int
db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs)
{
int ret=-1;
ctx->trans0 = NULL;
ctx->attrs0 = NULL;
if (max_trans > 0) { /* quite silly if not */
ctx->trans0 = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans,
"db_context->trans", db_trans_st);
if (!ctx->trans0) goto out;
}
if (max_attrs > 0) { /* quite silly if not */
ctx->attrs0 = ALLOC_BYTES_ST (sizeof (struct db_attr) * max_attrs,
"db_context->attrs", db_attrs_st);
if (!ctx->attrs0) goto out;
}
ret = 0;
out:
if (ret < 0 && ctx->trans0) {
PFREE_ST(ctx->trans0, db_trans_st);
ctx->trans0 = NULL;
}
ctx->max_trans = max_trans;
ctx->max_attrs = max_attrs;
ctx->trans_cur = ctx->trans0;
ctx->attrs_cur = ctx->attrs0;
ctx->prop.protoid = protoid;
ctx->prop.trans = ctx->trans0;
ctx->prop.trans_cnt = 0;
return ret;
}
/* Expand storage for transforms by number delta_trans */
static int
db_trans_expand(struct db_context *ctx, int delta_trans)
{
int ret = -1;
struct db_trans *new_trans, *old_trans;
int max_trans = ctx->max_trans + delta_trans;
int offset;
old_trans = ctx->trans0;
new_trans = ALLOC_BYTES_ST ( sizeof (struct db_trans) * max_trans,
"db_context->trans (expand)", db_trans_st);
if (!new_trans)
goto out;
memcpy(new_trans, old_trans, ctx->max_trans * sizeof(struct db_trans));
/* update trans0 (obviously) */
ctx->trans0 = ctx->prop.trans = new_trans;
/* update trans_cur (by offset) */
offset = (char *)(new_trans) - (char *)(old_trans);
{
char *cctx = (char *)(ctx->trans_cur);
cctx += offset;
ctx->trans_cur = (struct db_trans *)cctx;
}
/* update elem count */
ctx->max_trans = max_trans;
PFREE_ST(old_trans, db_trans_st);
ret = 0;
out:
return ret;
}
/*
* Expand storage for attributes by delta_attrs number AND
* rewrite trans->attr pointers
*/
static int
db_attrs_expand(struct db_context *ctx, int delta_attrs)
{
int ret = -1;
struct db_attr *new_attrs, *old_attrs;
struct db_trans *t;
int ti;
int max_attrs = ctx->max_attrs + delta_attrs;
int offset;
old_attrs = ctx->attrs0;
new_attrs = ALLOC_BYTES_ST ( sizeof (struct db_attr) * max_attrs,
"db_context->attrs (expand)", db_attrs_st);
if (!new_attrs)
goto out;
memcpy(new_attrs, old_attrs, ctx->max_attrs * sizeof(struct db_attr));
/* update attrs0 and attrs_cur (obviously) */
offset = (char *)(new_attrs) - (char *)(old_attrs);
{
char *actx = (char *)(ctx->attrs0);
actx += offset;
ctx->attrs0 = (struct db_attr *)actx;
actx = (char *)ctx->attrs_cur;
actx += offset;
ctx->attrs_cur = (struct db_attr *)actx;
}
/* for each transform, rewrite attrs pointer by offsetting it */
for (t=ctx->prop.trans, ti=0; ti < ctx->prop.trans_cnt; t++, ti++) {
char *actx = (char *)(t->attrs);
actx += offset;
t->attrs = (struct db_attr *)actx;
}
/* update elem count */
ctx->max_attrs = max_attrs;
PFREE_ST(old_attrs, db_attrs_st);
ret = 0;
out:
return ret;
}
/* Allocate a new db object */
struct db_context *
db_prop_new(u_int8_t protoid, int max_trans, int max_attrs)
{
struct db_context *ctx;
ctx = ALLOC_BYTES_ST ( sizeof (struct db_context), "db_context", db_context_st);
if (!ctx) goto out;
if (db_prop_init(ctx, protoid, max_trans, max_attrs) < 0) {
PFREE_ST(ctx, db_context_st);
ctx=NULL;
}
out:
return ctx;
}
/* Free a db object */
void
db_destroy(struct db_context *ctx)
{
if (ctx->trans0) PFREE_ST(ctx->trans0, db_trans_st);
if (ctx->attrs0) PFREE_ST(ctx->attrs0, db_attrs_st);
PFREE_ST(ctx, db_context_st);
}
/* Start a new transform, expand trans0 is needed */
int
db_trans_add(struct db_context *ctx, u_int8_t transid)
{
/* skip incrementing current trans pointer the 1st time*/
if (ctx->trans_cur && ctx->trans_cur->attr_cnt)
ctx->trans_cur++;
/*
* Strategy: if more space is needed, expand by
* <current_size>/2 + 1
*
* This happens to produce a "reasonable" sequence
* after few allocations, eg.:
* 0,1,2,4,8,13,20,31,47
*/
if ((ctx->trans_cur - ctx->trans0) >= ctx->max_trans) {
/* XXX:jjo if fails should shout and flag it */
if (db_trans_expand(ctx, ctx->max_trans/2 + 1)<0)
return -1;
}
ctx->trans_cur->transid = transid;
ctx->trans_cur->attrs=ctx->attrs_cur;
ctx->trans_cur->attr_cnt = 0;
ctx->prop.trans_cnt++;
return 0;
}
/* Add attr copy to current transform, expanding attrs0 if needed */
int
db_attr_add(struct db_context *ctx, const struct db_attr *a)
{
/*
* Strategy: if more space is needed, expand by
* <current_size>/2 + 1
*/
if ((ctx->attrs_cur - ctx->attrs0) >= ctx->max_attrs) {
/* XXX:jjo if fails should shout and flag it */
if (db_attrs_expand(ctx, ctx->max_attrs/2 + 1) < 0)
return -1;
}
*ctx->attrs_cur++=*a;
ctx->trans_cur->attr_cnt++;
return 0;
}
/* Add attr copy (by value) to current transform,
* expanding attrs0 if needed, just calls db_attr_add().
*/
int
db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val)
{
struct db_attr attr;
attr.type = type;
attr.val = val;
return db_attr_add (ctx, &attr);
}
#ifndef NO_DB_OPS_STATS
int
db_ops_show_status(void)
{
whack_log(RC_COMMENT, "stats " __FILE__ ": "
DB_OPS_STATS_DESC " :"
DB_OPS_STATS_STR("context")
DB_OPS_STATS_STR("trans")
DB_OPS_STATS_STR("attrs"),
DB_OPS_STATS_F(db_context_st),
DB_OPS_STATS_F(db_trans_st),
DB_OPS_STATS_F(db_attrs_st)
);
return 0;
}
#endif /* NO_DB_OPS_STATS */
/*
* From below to end just testing stuff ....
*/
#ifdef TEST
static void db_prop_print(struct db_prop *p)
{
struct db_trans *t;
struct db_attr *a;
int ti, ai;
enum_names *n, *n_at, *n_av;
printf("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid));
for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) {
switch( t->transid) {
case PROTO_ISAKMP:
n=&isakmp_transformid_names;break;
case PROTO_IPSEC_ESP:
n=&esp_transformid_names;break;
default:
continue;
}
printf(" transid=\"%s\"\n",
enum_name(n, t->transid));
for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) {
int i;
switch( t->transid) {
case PROTO_ISAKMP:
n_at=&oakley_attr_names;
i=a->type|ISAKMP_ATTR_AF_TV;
n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
break;
case PROTO_IPSEC_ESP:
n_at=&ipsec_attr_names;
i=a->type|ISAKMP_ATTR_AF_TV;
n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK];
break;
default:
continue;
}
printf(" type=\"%s\" value=\"%s\"\n",
enum_name(n_at, i),
enum_name(n_av, a->val));
}
}
}
static void db_print(struct db_context *ctx)
{
printf("trans_cur diff=%d, attrs_cur diff=%d\n",
ctx->trans_cur - ctx->trans0,
ctx->attrs_cur - ctx->attrs0);
db_prop_print(&ctx->prop);
}
void
passert_fail(const char *pred_str, const char *file_str, unsigned long line_no);
void abort(void);
void
passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
{
fprintf(stderr, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
abort(); /* exiting correctly doesn't always work */
}
int main(void) {
struct db_context *ctx=db_prop_new(PROTO_ISAKMP, 0, 0);
db_trans_add(ctx, KEY_IKE);
db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_3DES_CBC);
db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1024);
db_trans_add(ctx, KEY_IKE);
db_attr_add_values(ctx, OAKLEY_ENCRYPTION_ALGORITHM, OAKLEY_AES_CBC);
db_attr_add_values(ctx, OAKLEY_HASH_ALGORITHM, OAKLEY_MD5);
db_attr_add_values(ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
db_attr_add_values(ctx, OAKLEY_GROUP_DESCRIPTION, OAKLEY_GROUP_MODP1536);
db_trans_add(ctx, ESP_3DES);
db_attr_add_values(ctx, AUTH_ALGORITHM, AUTH_ALGORITHM_HMAC_SHA1);
db_print(ctx);
db_destroy(ctx);
return 0;
}
#endif
+56
View File
@@ -0,0 +1,56 @@
/* Dynamic db (proposal, transforms, attributes) handling.
* Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
*
* 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: db_ops.h,v 1.3 2004/09/17 12:37:37 as Exp $
*/
#ifndef _DB_OPS_H
#define _DB_OPS_H
/*
* Main db object, (quite proposal "oriented")
*/
#ifndef NO_DB_CONTEXT
struct db_context {
struct db_prop prop; /* proposal buffer (not pointer) */
struct db_trans *trans0; /* transf. list, dynamically sized */
struct db_trans *trans_cur; /* current transform ptr */
struct db_attr *attrs0; /* attr. list, dynamically sized */
struct db_attr *attrs_cur; /* current attribute ptr */
int max_trans; /* size of trans list */
int max_attrs; /* size of attrs list */
};
/*
* Allocate a new db object
*/
struct db_context * db_prop_new(u_int8_t protoid, int max_trans, int max_attrs);
/* Initialize object for proposal building */
int db_prop_init(struct db_context *ctx, u_int8_t protoid, int max_trans, int max_attrs);
/* Free all resourses for this db */
void db_destroy(struct db_context *ctx);
/* Start a new transform */
int db_trans_add(struct db_context *ctx, u_int8_t transid);
/* Add a new attribute by copying db_attr content */
int db_attr_add(struct db_context *db_ctx, const struct db_attr *attr);
/* Add a new attribute by value */
int db_attr_add_values(struct db_context *ctx, u_int16_t type, u_int16_t val);
/* Get proposal from db object */
static __inline__ struct db_prop *db_prop_get(struct db_context *ctx) {
return &ctx->prop;
}
/* Show stats (allocation, etc) */
#endif /* NO_DB_CONTEXT */
int db_ops_show_status(void);
#endif /* _DB_OPS_H */
+374
View File
@@ -0,0 +1,374 @@
/* misc. universal things
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: defs.c,v 1.9 2006/01/04 21:00:43 as Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <dirent.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "whack.h" /* for RC_LOG_SERIOUS */
const chunk_t empty_chunk = { NULL, 0 };
bool
all_zero(const unsigned char *m, size_t len)
{
size_t i;
for (i = 0; i != len; i++)
if (m[i] != '\0')
return FALSE;
return TRUE;
}
/* memory allocation
*
* LEAK_DETECTIVE puts a wrapper around each allocation and maintains
* a list of live ones. If a dead one is freed, an assertion MIGHT fail.
* If the live list is currupted, that will often be detected.
* In the end, report_leaks() is called, and the names of remaining
* live allocations are printed. At the moment, it is hoped, not that
* the list is empty, but that there will be no surprises.
*
* Accepted Leaks:
* - "struct iface" and "device name" (for "discovered" net interfaces)
* - "struct event in event_schedule()" (events not associated with states)
* - "Pluto lock name" (one only, needed until end -- why bother?)
*/
#ifdef LEAK_DETECTIVE
/* this magic number is 3671129837 decimal (623837458 complemented) */
#define LEAK_MAGIC 0xDAD0FEEDul
union mhdr {
struct {
const char *name;
union mhdr *older, *newer;
unsigned long magic;
} i; /* info */
unsigned long junk; /* force maximal alignment */
};
static union mhdr *allocs = NULL;
void *alloc_bytes(size_t size, const char *name)
{
union mhdr *p = malloc(sizeof(union mhdr) + size);
if (p == NULL)
exit_log("unable to malloc %lu bytes for %s"
, (unsigned long) size, name);
p->i.name = name;
p->i.older = allocs;
if (allocs != NULL)
allocs->i.newer = p;
allocs = p;
p->i.newer = NULL;
p->i.magic = LEAK_MAGIC;
memset(p+1, '\0', size);
return p+1;
}
void *
clone_bytes(const void *orig, size_t size, const char *name)
{
void *p = alloc_bytes(size, name);
memcpy(p, orig, size);
return p;
}
void
pfree(void *ptr)
{
union mhdr *p;
passert(ptr != NULL);
p = ((union mhdr *)ptr) - 1;
passert(p->i.magic == LEAK_MAGIC);
if (p->i.older != NULL)
{
passert(p->i.older->i.newer == p);
p->i.older->i.newer = p->i.newer;
}
if (p->i.newer == NULL)
{
passert(p == allocs);
allocs = p->i.older;
}
else
{
passert(p->i.newer->i.older == p);
p->i.newer->i.older = p->i.older;
}
p->i.magic = ~LEAK_MAGIC;
free(p);
}
void
report_leaks(void)
{
union mhdr
*p = allocs,
*pprev = NULL;
unsigned long n = 0;
while (p != NULL)
{
passert(p->i.magic == LEAK_MAGIC);
passert(pprev == p->i.newer);
pprev = p;
p = p->i.older;
n++;
if (p == NULL || pprev->i.name != p->i.name)
{
if (n != 1)
plog("leak: %lu * %s", n, pprev->i.name);
else
plog("leak: %s", pprev->i.name);
n = 0;
}
}
}
#else /* !LEAK_DETECTIVE */
void *alloc_bytes(size_t size, const char *name)
{
void *p = malloc(size);
if (p == NULL)
exit_log("unable to malloc %lu bytes for %s"
, (unsigned long) size, name);
memset(p, '\0', size);
return p;
}
void *clone_bytes(const void *orig, size_t size, const char *name)
{
void *p = malloc(size);
if (p == NULL)
exit_log("unable to malloc %lu bytes for %s"
, (unsigned long) size, name);
memcpy(p, orig, size);
return p;
}
#endif /* !LEAK_DETECTIVE */
/* Note that there may be as many as six IDs that are temporary at
* one time before unsharing the two ends of a connection. So we need
* at least six temporary buffers for DER_ASN1_DN IDs.
* We rotate them. Be careful!
*/
#define MAX_BUF 10
char*
temporary_cyclic_buffer(void)
{
static char buf[MAX_BUF][BUF_LEN]; /* MAX_BUF internal buffers */
static int counter = 0; /* cyclic counter */
if (++counter == MAX_BUF) counter = 0; /* next internal buffer */
return buf[counter]; /* assign temporary buffer */
}
/* concatenates two sub paths into a string with a maximum size of BUF_LEN
* use for temporary storage only
*/
const char*
concatenate_paths(const char *a, const char *b)
{
char *c;
if (*b == '/' || *b == '.')
return b;
c = temporary_cyclic_buffer();
snprintf(c, BUF_LEN, "%s/%s", a, b);
return c;
}
/* compare two chunks, returns zero if a equals b
* negative/positive if a is earlier/later in the alphabet than b
*/
bool
cmp_chunk(chunk_t a, chunk_t b)
{
int cmp_len, len, cmp_value;
cmp_len = a.len - b.len;
len = (cmp_len < 0)? a.len : b.len;
cmp_value = memcmp(a.ptr, b.ptr, len);
return (cmp_value == 0)? cmp_len : cmp_value;
};
/* moves a chunk to a memory position, chunk is freed afterwards
* position pointer is advanced after the insertion point
*/
void
mv_chunk(u_char **pos, chunk_t content)
{
if (content.len > 0)
{
chunkcpy(*pos, content);
freeanychunk(content);
}
}
/*
* write the binary contents of a chunk_t to a file
*/
bool
write_chunk(const char *filename, const char *label, chunk_t ch
, mode_t mask, bool force)
{
mode_t oldmask;
FILE *fd;
if (!force)
{
fd = fopen(filename, "r");
if (fd)
{
fclose(fd);
plog(" %s file '%s' already exists", label, filename);
return FALSE;
}
}
/* set umask */
oldmask = umask(mask);
fd = fopen(filename, "w");
if (fd)
{
fwrite(ch.ptr, sizeof(u_char), ch.len, fd);
fclose(fd);
plog(" written %s file '%s' (%d bytes)", label, filename, (int)ch.len);
umask(oldmask);
return TRUE;
}
else
{
plog(" could not open %s file '%s' for writing", label, filename);
umask(oldmask);
return FALSE;
}
}
/* Names of the months */
static const char* months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
/*
* Display a date either in local or UTC time
*/
char*
timetoa(const time_t *time, bool utc)
{
static char buf[TIMETOA_BUF];
if (*time == UNDEFINED_TIME)
sprintf(buf, "--- -- --:--:--%s----", (utc)?" UTC ":" ");
else
{
struct tm *t = (utc)? gmtime(time) : localtime(time);
sprintf(buf, "%s %02d %02d:%02d:%02d%s%04d",
months[t->tm_mon], t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec,
(utc)?" UTC ":" ", t->tm_year + 1900
);
}
return buf;
}
/* checks if the expiration date has been reached and
* warns during the warning_interval of the imminent
* expiry. strict=TRUE declares a fatal error,
* strict=FALSE issues a warning upon expiry.
*/
const char*
check_expiry(time_t expiration_date, int warning_interval, bool strict)
{
time_t now;
int time_left;
if (expiration_date == UNDEFINED_TIME)
return "ok (expires never)";
/* determine the current time */
time(&now);
time_left = (expiration_date - now);
if (time_left < 0)
return strict? "fatal (expired)" : "warning (expired)";
if (time_left > 86400*warning_interval)
return "ok";
{
static char buf[35]; /* temporary storage */
const char* unit = "second";
if (time_left > 172800)
{
time_left /= 86400;
unit = "day";
}
else if (time_left > 7200)
{
time_left /= 3600;
unit = "hour";
}
else if (time_left > 120)
{
time_left /= 60;
unit = "minute";
}
snprintf(buf, 35, "warning (expires in %d %s%s)", time_left,
unit, (time_left == 1)?"":"s");
return buf;
}
}
/*
* Filter eliminating the directory entries '.' and '..'
*/
int
file_select(const struct dirent *entry)
{
return strcmp(entry->d_name, "." ) &&
strcmp(entry->d_name, "..");
}
+145
View File
@@ -0,0 +1,145 @@
/* misc. universal things
* Copyright (C) 1997 Angelos D. Keromytis.
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: defs.h,v 1.10 2006/01/04 21:00:43 as Exp $
*/
#ifndef _DEFS_H
#define _DEFS_H
#include <sys/types.h>
#ifdef KLIPS
# define USED_BY_KLIPS /* ignore */
#else
# define USED_BY_KLIPS UNUSED
#endif
#ifdef DEBUG
# define USED_BY_DEBUG /* ignore */
#else
# define USED_BY_DEBUG UNUSED
#endif
/* Length of temporary buffers */
#define BUF_LEN 512
/* type of serial number of a state object
* Needed in connections.h and state.h; here to simplify dependencies.
*/
typedef unsigned long so_serial_t;
#define SOS_NOBODY 0 /* null serial number */
#define SOS_FIRST 1 /* first normal serial number */
/* memory allocation */
extern void *alloc_bytes(size_t size, const char *name);
#define alloc_thing(thing, name) (alloc_bytes(sizeof(thing), (name)))
extern void *clone_bytes(const void *orig, size_t size, const char *name);
#define clone_thing(orig, name) clone_bytes((const void *)&(orig), sizeof(orig), (name))
#define clone_str(str, name) \
((str) == NULL? NULL : clone_bytes((str), strlen((str))+1, (name)))
#ifdef LEAK_DETECTIVE
extern void pfree(void *ptr);
extern void report_leaks(void);
#else
# define pfree(ptr) free(ptr) /* ordinary stdc free */
#endif
#define pfreeany(p) { if ((p) != NULL) pfree(p); }
#define replace(p, q) { pfreeany(p); (p) = (q); }
/* chunk is a simple pointer-and-size abstraction */
struct chunk {
u_char *ptr;
size_t len;
};
typedef struct chunk chunk_t;
#define setchunk(ch, addr, size) { (ch).ptr = (addr); (ch).len = (size); }
#define strchunk(str) { str, sizeof(str) }
/* NOTE: freeanychunk, unlike pfreeany, NULLs .ptr */
#define freeanychunk(ch) { pfreeany((ch).ptr); (ch).ptr = NULL; }
#define clonetochunk(ch, addr, size, name) \
{ (ch).ptr = clone_bytes((addr), (ch).len = (size), name); }
#define clonereplacechunk(ch, addr, size, name) \
{ pfreeany((ch).ptr); clonetochunk(ch, addr, size, name); }
#define chunkcpy(dst, chunk) \
{ memcpy(dst, chunk.ptr, chunk.len); dst += chunk.len;}
#define same_chunk(a, b) \
(a).len == (b).len && memcmp((a).ptr, (b).ptr, (b).len) == 0
extern char* temporary_cyclic_buffer(void);
extern const char* concatenate_paths(const char *a, const char *b);
extern const chunk_t empty_chunk;
/* compare two chunks */
extern bool cmp_chunk(chunk_t a, chunk_t b);
/* move a chunk to a memory position and free it after insertion */
extern void mv_chunk(u_char **pos, chunk_t content);
/* write the binary contents of a chunk_t to a file */
extern bool write_chunk(const char *filename, const char *label, chunk_t ch
,mode_t mask, bool force);
/* display a date either in local or UTC time */
extern char* timetoa(const time_t *time, bool utc);
/* warns a predefined interval before expiry */
extern const char* check_expiry(time_t expiration_date,
int warning_interval, bool strict);
#define MAX_PROMPT_PASS_TRIALS 5
#define PROMPT_PASS_LEN 64
/* struct used to prompt for a secret passphrase
* from a console with file descriptor fd
*/
typedef struct {
char secret[PROMPT_PASS_LEN+1];
bool prompt;
int fd;
} prompt_pass_t;
/* no time defined in time_t */
#define UNDEFINED_TIME 0
/* size of timetoa string buffer */
#define TIMETOA_BUF 30
/* filter eliminating the directory entries '.' and '..' */
typedef struct dirent dirent_t;
extern int file_select(const dirent_t *entry);
/* cleanly exit Pluto */
extern void exit_pluto(int /*status*/) NEVER_RETURNS;
/* zero all bytes */
#define zero(x) memset((x), '\0', sizeof(*(x)))
/* are all bytes 0? */
extern bool all_zero(const unsigned char *m, size_t len);
/* pad_up(n, m) is the amount to add to n to make it a multiple of m */
#define pad_up(n, m) (((m) - 1) - (((n) + (m) - 1) % (m)))
#endif /* _DEFS_H */
+2427
View File
File diff suppressed because it is too large Load Diff
+100
View File
@@ -0,0 +1,100 @@
/* demultiplex incoming IKE messages
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
*
* 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: demux.h,v 1.4 2004/07/22 22:57:25 as Exp $
*/
#include "packet.h"
struct state; /* forward declaration of tag */
extern void init_demux(void);
#ifdef NAT_TRAVERSAL
#define send_packet(st,wh) _send_packet(st,wh,TRUE)
extern bool _send_packet(struct state *st, const char *where, bool verbose);
#else
extern bool send_packet(struct state *st, const char *where);
#endif
extern void comm_handle(const struct iface *ifp);
extern u_int8_t reply_buffer[MAX_OUTPUT_UDP_SIZE];
/* State transition function infrastructure
*
* com_handle parses a message, decides what state object it applies to,
* and calls the appropriate state transition function (STF).
* These declarations define the interface to these functions.
*
* Each STF must be able to be restarted up to any failure point:
* a later message will cause the state to be re-entered. This
* explains the use of the replace macro and the care in handling
* MP_INT members of struct state.
*/
struct payload_digest {
pb_stream pbs;
union payload payload;
struct payload_digest *next; /* of same kind */
};
/* message digest
* Note: raw_packet and packet_pbs are "owners" of space on heap.
*/
struct msg_digest {
struct msg_digest *next; /* for free list */
chunk_t raw_packet; /* if encrypted, received packet before decryption */
const struct iface *iface; /* interface on which message arrived */
ip_address sender; /* where message came from */
u_int16_t sender_port; /* host order */
pb_stream packet_pbs; /* whole packet */
pb_stream message_pbs; /* message to be processed */
struct isakmp_hdr hdr; /* message's header */
bool encrypted; /* was it encrypted? */
enum state_kind from_state; /* state we started in */
const struct state_microcode *smc; /* microcode for initial state */
struct state *st; /* current state object */
pb_stream reply; /* room for reply */
pb_stream rbody; /* room for reply body (after header) */
notification_t note; /* reason for failure */
bool dpd; /* peer supports RFC 3706 DPD */
bool openpgp; /* peer supports OpenPGP certificates */
# define PAYLIMIT 20
struct payload_digest
digest[PAYLIMIT],
*digest_roof,
*chain[ISAKMP_NEXT_ROOF];
#ifdef NAT_TRAVERSAL
unsigned short nat_traversal_vid;
#endif
};
extern void release_md(struct msg_digest *md);
/* status for state-transition-function
* Note: STF_FAIL + notification_t means fail with that notification
*/
typedef enum {
STF_IGNORE, /* don't respond */
STF_SUSPEND, /* unfinished -- don't release resources */
STF_OK, /* success */
STF_INTERNAL_ERROR, /* discard everything, we failed */
STF_FAIL /* discard everything, something failed. notification_t added. */
} stf_status;
typedef stf_status state_transition_fn(struct msg_digest *md);
extern void complete_state_transition(struct msg_digest **mdp, stf_status result);
extern void free_md_pool(void);
+1962
View File
File diff suppressed because it is too large Load Diff
+84
View File
@@ -0,0 +1,84 @@
/* Find public key in DNS
* Copyright (C) 2000-2002 D. Hugh Redelmeier.
*
* 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: dnskey.h,v 1.1 2004/03/15 20:35:28 as Exp $
*/
extern int
adns_qfd, /* file descriptor for sending queries to adns */
adns_afd; /* file descriptor for receiving answers from adns */
extern const char *pluto_adns_option; /* path from --pluto_adns */
extern void init_adns(void);
extern void stop_adns(void);
extern void handle_adns_answer(void);
extern bool unsent_ADNS_queries;
extern void send_unsent_ADNS_queries(void);
/* (common prefix of) stuff remembered between async query and answer.
* Filled in by start_adns_query.
* Freed by call to release_adns_continuation.
*/
struct adns_continuation; /* forward declaration (not far!) */
typedef void (*cont_fn_t)(struct adns_continuation *cr, err_t ugh);
struct adns_continuation {
unsigned long qtid; /* query transaction id number */
int type; /* T_TXT or T_KEY, selecting rr type of interest */
cont_fn_t cont_fn; /* function to carry on suspended work */
struct id id; /* subject of query */
bool sgw_specified;
struct id sgw_id; /* peer, if constrained */
lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */
struct gw_info *gateways_from_dns; /* answer, if looking for our TXT rrs */
#ifdef USE_KEYRR
struct pubkey_list *keys_from_dns; /* answer, if looking for KEY rrs */
#endif
struct adns_continuation *previous, *next;
struct pubkey *last_info; /* the last structure we accumulated */
#ifdef USE_LWRES
bool used; /* have we called the cont_fn yet? */
struct {
u_char name_buf[NS_MAXDNAME + 2];
} query;
#else /* ! USE_LWRES */
struct adns_query query;
#endif /* ! USE_LWRES */
};
extern err_t start_adns_query(const struct id *id /* domain to query */
, const struct id *sgw_id /* if non-null, any accepted gw_info must match */
, int type /* T_TXT or T_KEY, selecting rr type of interest */
, cont_fn_t cont_fn /* continuation function */
, struct adns_continuation *cr);
/* Gateway info gleaned from reverse DNS of client */
struct gw_info {
unsigned refcnt; /* reference counted! */
unsigned pref; /* preference: lower is better */
#define NO_TIME ((time_t) -2) /* time_t value meaning "not_yet" */
struct id client_id; /* id of client of peer */
struct id gw_id; /* id of peer (if id_is_ipaddr, .ip_addr is address) */
bool gw_key_present;
struct pubkey *key;
struct gw_info *next;
};
extern void gw_addref(struct gw_info *gw)
, gw_delref(struct gw_info **gwp);
extern void reset_adns_restart_count(void);
+476
View File
@@ -0,0 +1,476 @@
/* dsa.c - DSA signature scheme
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG 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.
*
* GnuPG 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef PLUTO
#include <gmp.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "rnd.h"
#include "gcryptfix.h"
#else /*! PLUTO */
/* #include <config.h> */
#endif /* !PLUTO */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef PLUTO
/* #include <assert.h> */
/* #include "util.h" */
/* #include "mpi.h" */
/* #include "cipher.h" */
#endif
#include "dsa.h"
typedef struct {
MPI p; /* prime */
MPI q; /* group order */
MPI g; /* group generator */
MPI y; /* g^x mod p */
} DSA_public_key;
typedef struct {
MPI p; /* prime */
MPI q; /* group order */
MPI g; /* group generator */
MPI y; /* g^x mod p */
MPI x; /* secret exponent */
} DSA_secret_key;
static MPI gen_k( MPI q );
static void test_keys( DSA_secret_key *sk, unsigned qbits );
static int check_secret_key( DSA_secret_key *sk );
static void generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors );
static void sign(MPI r, MPI s, MPI input, DSA_secret_key *skey);
static int verify(MPI r, MPI s, MPI input, DSA_public_key *pkey);
static void
progress( int c )
{
fputc( c, stderr );
}
/****************
* Generate a random secret exponent k less than q
*/
static MPI
gen_k( MPI q )
{
MPI k = mpi_alloc_secure( mpi_get_nlimbs(q) );
unsigned int nbits = mpi_get_nbits(q);
unsigned int nbytes = (nbits+7)/8;
char *rndbuf = NULL;
if( DBG_CIPHER )
log_debug("choosing a random k ");
for(;;) {
if( DBG_CIPHER )
progress('.');
if( !rndbuf || nbits < 32 ) {
m_free(rndbuf);
rndbuf = get_random_bits( nbits, 1, 1 );
}
else { /* change only some of the higher bits */
/* we could imporove this by directly requesting more memory
* at the first call to get_random_bits() and use this the here
* maybe it is easier to do this directly in random.c */
char *pp = get_random_bits( 32, 1, 1 );
memcpy( rndbuf,pp, 4 );
m_free(pp);
}
mpi_set_buffer( k, rndbuf, nbytes, 0 );
if( mpi_test_bit( k, nbits-1 ) )
mpi_set_highbit( k, nbits-1 );
else {
mpi_set_highbit( k, nbits-1 );
mpi_clear_bit( k, nbits-1 );
}
if( !(mpi_cmp( k, q ) < 0) ) { /* check: k < q */
if( DBG_CIPHER )
progress('+');
continue; /* no */
}
if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
if( DBG_CIPHER )
progress('-');
continue; /* no */
}
break; /* okay */
}
m_free(rndbuf);
if( DBG_CIPHER )
progress('\n');
return k;
}
static void
test_keys( DSA_secret_key *sk, unsigned qbits )
{
DSA_public_key pk;
MPI test = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
MPI out1_a = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
MPI out1_b = mpi_alloc( qbits / BITS_PER_MPI_LIMB );
pk.p = sk->p;
pk.q = sk->q;
pk.g = sk->g;
pk.y = sk->y;
/*mpi_set_bytes( test, qbits, get_random_byte, 0 );*/
{ char *p = get_random_bits( qbits, 0, 0 );
mpi_set_buffer( test, p, (qbits+7)/8, 0 );
m_free(p);
}
sign( out1_a, out1_b, test, sk );
if( !verify( out1_a, out1_b, test, &pk ) )
log_fatal("DSA:: sign, verify failed\n");
mpi_free( test );
mpi_free( out1_a );
mpi_free( out1_b );
}
/****************
* Generate a DSA key pair with a key of size NBITS
* Returns: 2 structures filled with all needed values
* and an array with the n-1 factors of (p-1)
*/
static void
generate( DSA_secret_key *sk, unsigned nbits, MPI **ret_factors )
{
MPI p; /* the prime */
MPI q; /* the 160 bit prime factor */
MPI g; /* the generator */
MPI y; /* g^x mod p */
MPI x; /* the secret exponent */
MPI h, e; /* helper */
unsigned qbits;
byte *rndbuf;
assert( nbits >= 512 && nbits <= 1024 );
qbits = 160;
p = generate_elg_prime( 1, nbits, qbits, NULL, ret_factors );
/* get q out of factors */
q = mpi_copy((*ret_factors)[0]);
if( mpi_get_nbits(q) != qbits )
BUG();
/* find a generator g (h and e are helpers)*/
/* e = (p-1)/q */
e = mpi_alloc( mpi_get_nlimbs(p) );
mpi_sub_ui( e, p, 1 );
mpi_fdiv_q( e, e, q );
g = mpi_alloc( mpi_get_nlimbs(p) );
h = mpi_alloc_set_ui( 1 ); /* we start with 2 */
do {
mpi_add_ui( h, h, 1 );
/* g = h^e mod p */
mpi_powm( g, h, e, p );
} while( !mpi_cmp_ui( g, 1 ) ); /* continue until g != 1 */
/* select a random number which has these properties:
* 0 < x < q-1
* This must be a very good random number because this
* is the secret part. */
if( DBG_CIPHER )
log_debug("choosing a random x ");
assert( qbits >= 160 );
x = mpi_alloc_secure( mpi_get_nlimbs(q) );
mpi_sub_ui( h, q, 1 ); /* put q-1 into h */
rndbuf = NULL;
do {
if( DBG_CIPHER )
progress('.');
if( !rndbuf )
rndbuf = get_random_bits( qbits, 2, 1 );
else { /* change only some of the higher bits (= 2 bytes)*/
char *r = get_random_bits( 16, 2, 1 );
memcpy(rndbuf, r, 16/8 );
m_free(r);
}
mpi_set_buffer( x, rndbuf, (qbits+7)/8, 0 );
mpi_clear_highbit( x, qbits+1 );
} while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, h )<0 ) );
m_free(rndbuf);
mpi_free( e );
mpi_free( h );
/* y = g^x mod p */
y = mpi_alloc( mpi_get_nlimbs(p) );
mpi_powm( y, g, x, p );
if( DBG_CIPHER ) {
progress('\n');
log_mpidump("dsa p= ", p );
log_mpidump("dsa q= ", q );
log_mpidump("dsa g= ", g );
log_mpidump("dsa y= ", y );
log_mpidump("dsa x= ", x );
}
/* copy the stuff to the key structures */
sk->p = p;
sk->q = q;
sk->g = g;
sk->y = y;
sk->x = x;
/* now we can test our keys (this should never fail!) */
test_keys( sk, qbits );
}
/****************
* Test whether the secret key is valid.
* Returns: if this is a valid key.
*/
static int
check_secret_key( DSA_secret_key *sk )
{
int rc;
MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
mpi_powm( y, sk->g, sk->x, sk->p );
rc = !mpi_cmp( y, sk->y );
mpi_free( y );
return rc;
}
/****************
* Make a DSA signature from HASH and put it into r and s.
*/
static void
sign(MPI r, MPI s, MPI hash, DSA_secret_key *skey )
{
MPI k;
MPI kinv;
MPI tmp;
/* select a random k with 0 < k < q */
k = gen_k( skey->q );
/* r = (a^k mod p) mod q */
mpi_powm( r, skey->g, k, skey->p );
mpi_fdiv_r( r, r, skey->q );
/* kinv = k^(-1) mod q */
kinv = mpi_alloc( mpi_get_nlimbs(k) );
mpi_invm(kinv, k, skey->q );
/* s = (kinv * ( hash + x * r)) mod q */
tmp = mpi_alloc( mpi_get_nlimbs(skey->p) );
mpi_mul( tmp, skey->x, r );
mpi_add( tmp, tmp, hash );
mpi_mulm( s , kinv, tmp, skey->q );
mpi_free(k);
mpi_free(kinv);
mpi_free(tmp);
}
/****************
* Returns true if the signature composed from R and S is valid.
*/
static int
verify(MPI r, MPI s, MPI hash, DSA_public_key *pkey )
{
int rc;
MPI w, u1, u2, v;
MPI base[3];
MPI exp[3];
if( !(mpi_cmp_ui( r, 0 ) > 0 && mpi_cmp( r, pkey->q ) < 0) )
return 0; /* assertion 0 < r < q failed */
if( !(mpi_cmp_ui( s, 0 ) > 0 && mpi_cmp( s, pkey->q ) < 0) )
return 0; /* assertion 0 < s < q failed */
w = mpi_alloc( mpi_get_nlimbs(pkey->q) );
u1 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
u2 = mpi_alloc( mpi_get_nlimbs(pkey->q) );
v = mpi_alloc( mpi_get_nlimbs(pkey->p) );
/* w = s^(-1) mod q */
mpi_invm( w, s, pkey->q );
/* u1 = (hash * w) mod q */
mpi_mulm( u1, hash, w, pkey->q );
/* u2 = r * w mod q */
mpi_mulm( u2, r, w, pkey->q );
/* v = g^u1 * y^u2 mod p mod q */
base[0] = pkey->g; exp[0] = u1;
base[1] = pkey->y; exp[1] = u2;
base[2] = NULL; exp[2] = NULL;
mpi_mulpowm( v, base, exp, pkey->p );
mpi_fdiv_r( v, v, pkey->q );
rc = !mpi_cmp( v, r );
mpi_free(w);
mpi_free(u1);
mpi_free(u2);
mpi_free(v);
return rc;
}
/*********************************************
************** interface ******************
*********************************************/
int
dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
{
DSA_secret_key sk;
if( algo != PUBKEY_ALGO_DSA )
return G10ERR_PUBKEY_ALGO;
generate( &sk, nbits, retfactors );
skey[0] = sk.p;
skey[1] = sk.q;
skey[2] = sk.g;
skey[3] = sk.y;
skey[4] = sk.x;
return 0;
}
int
dsa_check_secret_key( int algo, MPI *skey )
{
DSA_secret_key sk;
if( algo != PUBKEY_ALGO_DSA )
return G10ERR_PUBKEY_ALGO;
if( !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
return G10ERR_BAD_MPI;
sk.p = skey[0];
sk.q = skey[1];
sk.g = skey[2];
sk.y = skey[3];
sk.x = skey[4];
if( !check_secret_key( &sk ) )
return G10ERR_BAD_SECKEY;
return 0;
}
int
dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
{
DSA_secret_key sk;
if( algo != PUBKEY_ALGO_DSA )
return G10ERR_PUBKEY_ALGO;
if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] )
return G10ERR_BAD_MPI;
sk.p = skey[0];
sk.q = skey[1];
sk.g = skey[2];
sk.y = skey[3];
sk.x = skey[4];
resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
sign( resarr[0], resarr[1], data, &sk );
return 0;
}
int
dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI) UNUSED, void *opaquev UNUSED)
{
DSA_public_key pk;
if( algo != PUBKEY_ALGO_DSA )
return G10ERR_PUBKEY_ALGO;
if( !data[0] || !data[1] || !hash
|| !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] )
return G10ERR_BAD_MPI;
pk.p = pkey[0];
pk.q = pkey[1];
pk.g = pkey[2];
pk.y = pkey[3];
if( !verify( data[0], data[1], hash, &pk ) )
return G10ERR_BAD_SIGN;
return 0;
}
unsigned
dsa_get_nbits( int algo, MPI *pkey )
{
if( algo != PUBKEY_ALGO_DSA )
return 0;
return mpi_get_nbits( pkey[0] );
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
* Usage: Bit 0 set : allows signing
* 1 set : allows encryption
*/
const char *
dsa_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
int *use )
{
*npkey = 4;
*nskey = 5;
*nenc = 0;
*nsig = 2;
switch( algo ) {
case PUBKEY_ALGO_DSA: *use = PUBKEY_USAGE_SIG; return "DSA";
default: *use = 0; return NULL;
}
}
+32
View File
@@ -0,0 +1,32 @@
/* dsa.h - DSA signature scheme
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG 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.
*
* GnuPG 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_DSA_H
#define G10_DSA_H
int dsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
int dsa_check_secret_key( int algo, MPI *skey );
int dsa_sign( int algo, MPI *resarr, MPI data, MPI *skey );
int dsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI), void *opaquev );
unsigned dsa_get_nbits( int algo, MPI *pkey );
const char *dsa_get_info( int algo, int *npkey, int *nskey,
int *nenc, int *nsig, int *use );
#endif /*G10_DSA_H*/
+613
View File
@@ -0,0 +1,613 @@
/* elgamal.c - ElGamal Public Key encryption
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* For a description of the algorithm, see:
* Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
* ISBN 0-471-11709-9. Pages 476 ff.
*
* This file is part of GnuPG.
*
* GnuPG 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.
*
* GnuPG 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef PLUTO
#include <gmp.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "rnd.h"
#include "gcryptfix.h"
#else /*! PLUTO */
/* #include <config.h> */
#endif /* !PLUTO */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef PLUTO
/* #include "util.h" */
/* #include "mpi.h" */
/* #include "cipher.h" */
#endif
#include "elgamal.h"
typedef struct {
MPI p; /* prime */
MPI g; /* group generator */
MPI y; /* g^x mod p */
} ELG_public_key;
typedef struct {
MPI p; /* prime */
MPI g; /* group generator */
MPI y; /* g^x mod p */
MPI x; /* secret exponent */
} ELG_secret_key;
static void test_keys( ELG_secret_key *sk, unsigned nbits );
static MPI gen_k( MPI p );
static void generate( ELG_secret_key *sk, unsigned nbits, MPI **factors );
static int check_secret_key( ELG_secret_key *sk );
static void encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey );
static void decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey );
static void sign(MPI a, MPI b, MPI input, ELG_secret_key *skey);
static int verify(MPI a, MPI b, MPI input, ELG_public_key *pkey);
static void
progress( int c )
{
fputc( c, stderr );
}
static void
test_keys( ELG_secret_key *sk, unsigned nbits )
{
ELG_public_key pk;
MPI test = mpi_alloc( 0 );
MPI out1_a = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
MPI out1_b = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
MPI out2 = mpi_alloc( nbits / BITS_PER_MPI_LIMB );
pk.p = sk->p;
pk.g = sk->g;
pk.y = sk->y;
/*mpi_set_bytes( test, nbits, get_random_byte, 0 );*/
{ char *p = get_random_bits( nbits, 0, 0 );
mpi_set_buffer( test, p, (nbits+7)/8, 0 );
m_free(p);
}
encrypt( out1_a, out1_b, test, &pk );
decrypt( out2, out1_a, out1_b, sk );
if( mpi_cmp( test, out2 ) )
log_fatal("ElGamal operation: encrypt, decrypt failed\n");
sign( out1_a, out1_b, test, sk );
if( !verify( out1_a, out1_b, test, &pk ) )
log_fatal("ElGamal operation: sign, verify failed\n");
mpi_free( test );
mpi_free( out1_a );
mpi_free( out1_b );
mpi_free( out2 );
}
/****************
* generate a random secret exponent k from prime p, so
* that k is relatively prime to p-1
*/
static MPI
gen_k( MPI p )
{
MPI k = mpi_alloc_secure( 0 );
MPI temp = mpi_alloc( mpi_get_nlimbs(p) );
MPI p_1 = mpi_copy(p);
unsigned int nbits = mpi_get_nbits(p);
unsigned int nbytes = (nbits+7)/8;
char *rndbuf = NULL;
if( DBG_CIPHER )
log_debug("choosing a random k ");
mpi_sub_ui( p_1, p, 1);
for(;;) {
if( DBG_CIPHER )
progress('.');
if( !rndbuf || nbits < 32 ) {
m_free(rndbuf);
rndbuf = get_random_bits( nbits, 1, 1 );
}
else { /* change only some of the higher bits */
/* we could imporove this by directly requesting more memory
* at the first call to get_random_bits() and use this the here
* maybe it is easier to do this directly in random.c */
char *pp = get_random_bits( 32, 1, 1 );
memcpy( rndbuf,pp, 4 );
m_free(pp);
}
mpi_set_buffer( k, rndbuf, nbytes, 0 );
for(;;) {
/* make sure that the number is of the exact lenght */
if( mpi_test_bit( k, nbits-1 ) )
mpi_set_highbit( k, nbits-1 );
else {
mpi_set_highbit( k, nbits-1 );
mpi_clear_bit( k, nbits-1 );
}
if( !(mpi_cmp( k, p_1 ) < 0) ) { /* check: k < (p-1) */
if( DBG_CIPHER )
progress('+');
break; /* no */
}
if( !(mpi_cmp_ui( k, 0 ) > 0) ) { /* check: k > 0 */
if( DBG_CIPHER )
progress('-');
break; /* no */
}
if( mpi_gcd( temp, k, p_1 ) )
goto found; /* okay, k is relatively prime to (p-1) */
mpi_add_ui( k, k, 1 );
}
}
found:
m_free(rndbuf);
if( DBG_CIPHER )
progress('\n');
mpi_free(p_1);
mpi_free(temp);
return k;
}
/****************
* Generate a key pair with a key of size NBITS
* Returns: 2 structures filles with all needed values
* and an array with n-1 factors of (p-1)
*/
static void
generate( ELG_secret_key *sk, unsigned nbits, MPI **ret_factors )
{
MPI p; /* the prime */
MPI p_min1;
MPI g;
MPI x; /* the secret exponent */
MPI y;
MPI temp;
unsigned qbits;
byte *rndbuf;
p_min1 = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
temp = mpi_alloc( (nbits+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB );
if( nbits < 512 )
qbits = 120;
else if( nbits <= 1024 )
qbits = 160;
else if( nbits <= 2048 )
qbits = 200;
else
qbits = 240;
g = mpi_alloc(1);
p = generate_elg_prime( 0, nbits, qbits, g, ret_factors );
mpi_sub_ui(p_min1, p, 1);
/* select a random number which has these properties:
* 0 < x < p-1
* This must be a very good random number because this is the
* secret part. The prime is public and may be shared anyway,
* so a random generator level of 1 is used for the prime.
*/
x = mpi_alloc_secure( nbits/BITS_PER_MPI_LIMB );
if( DBG_CIPHER )
log_debug("choosing a random x ");
rndbuf = NULL;
do {
if( DBG_CIPHER )
progress('.');
if( rndbuf ) { /* change only some of the higher bits */
if( nbits < 16 ) {/* should never happen ... */
m_free(rndbuf);
rndbuf = get_random_bits( nbits, 2, 1 );
}
else {
char *r = get_random_bits( 16, 2, 1 );
memcpy(rndbuf, r, 16/8 );
m_free(r);
}
}
else
rndbuf = get_random_bits( nbits, 2, 1 );
mpi_set_buffer( x, rndbuf, (nbits+7)/8, 0 );
mpi_clear_highbit( x, nbits+1 );
} while( !( mpi_cmp_ui( x, 0 )>0 && mpi_cmp( x, p_min1 )<0 ) );
m_free(rndbuf);
y = mpi_alloc(nbits/BITS_PER_MPI_LIMB);
mpi_powm( y, g, x, p );
if( DBG_CIPHER ) {
progress('\n');
log_mpidump("elg p= ", p );
log_mpidump("elg g= ", g );
log_mpidump("elg y= ", y );
log_mpidump("elg x= ", x );
}
/* copy the stuff to the key structures */
sk->p = p;
sk->g = g;
sk->y = y;
sk->x = x;
/* now we can test our keys (this should never fail!) */
test_keys( sk, nbits - 64 );
mpi_free( p_min1 );
mpi_free( temp );
}
/****************
* Test whether the secret key is valid.
* Returns: if this is a valid key.
*/
static int
check_secret_key( ELG_secret_key *sk )
{
int rc;
MPI y = mpi_alloc( mpi_get_nlimbs(sk->y) );
mpi_powm( y, sk->g, sk->x, sk->p );
rc = !mpi_cmp( y, sk->y );
mpi_free( y );
return rc;
}
static void
encrypt(MPI a, MPI b, MPI input, ELG_public_key *pkey )
{
MPI k;
/* Note: maybe we should change the interface, so that it
* is possible to check that input is < p and return an
* error code.
*/
k = gen_k( pkey->p );
mpi_powm( a, pkey->g, k, pkey->p );
/* b = (y^k * input) mod p
* = ((y^k mod p) * (input mod p)) mod p
* and because input is < p
* = ((y^k mod p) * input) mod p
*/
mpi_powm( b, pkey->y, k, pkey->p );
mpi_mulm( b, b, input, pkey->p );
#if 0
if( DBG_CIPHER ) {
log_mpidump("elg encrypted y= ", pkey->y);
log_mpidump("elg encrypted p= ", pkey->p);
log_mpidump("elg encrypted k= ", k);
log_mpidump("elg encrypted M= ", input);
log_mpidump("elg encrypted a= ", a);
log_mpidump("elg encrypted b= ", b);
}
#endif
mpi_free(k);
}
static void
decrypt(MPI output, MPI a, MPI b, ELG_secret_key *skey )
{
MPI t1 = mpi_alloc_secure( mpi_get_nlimbs( skey->p ) );
/* output = b/(a^x) mod p */
mpi_powm( t1, a, skey->x, skey->p );
mpi_invm( t1, t1, skey->p );
mpi_mulm( output, b, t1, skey->p );
#if 0
if( DBG_CIPHER ) {
log_mpidump("elg decrypted x= ", skey->x);
log_mpidump("elg decrypted p= ", skey->p);
log_mpidump("elg decrypted a= ", a);
log_mpidump("elg decrypted b= ", b);
log_mpidump("elg decrypted M= ", output);
}
#endif
mpi_free(t1);
}
/****************
* Make an Elgamal signature out of INPUT
*/
static void
sign(MPI a, MPI b, MPI input, ELG_secret_key *skey )
{
MPI k;
MPI t = mpi_alloc( mpi_get_nlimbs(a) );
MPI inv = mpi_alloc( mpi_get_nlimbs(a) );
MPI p_1 = mpi_copy(skey->p);
/*
* b = (t * inv) mod (p-1)
* b = (t * inv(k,(p-1),(p-1)) mod (p-1)
* b = (((M-x*a) mod (p-1)) * inv(k,(p-1),(p-1))) mod (p-1)
*
*/
mpi_sub_ui(p_1, p_1, 1);
k = gen_k( skey->p );
mpi_powm( a, skey->g, k, skey->p );
mpi_mul(t, skey->x, a );
mpi_subm(t, input, t, p_1 );
while( mpi_is_neg(t) )
mpi_add(t, t, p_1);
mpi_invm(inv, k, p_1 );
mpi_mulm(b, t, inv, p_1 );
#if 0
if( DBG_CIPHER ) {
log_mpidump("elg sign p= ", skey->p);
log_mpidump("elg sign g= ", skey->g);
log_mpidump("elg sign y= ", skey->y);
log_mpidump("elg sign x= ", skey->x);
log_mpidump("elg sign k= ", k);
log_mpidump("elg sign M= ", input);
log_mpidump("elg sign a= ", a);
log_mpidump("elg sign b= ", b);
}
#endif
mpi_free(k);
mpi_free(t);
mpi_free(inv);
mpi_free(p_1);
}
/****************
* Returns true if the signature composed of A and B is valid.
*/
static int
verify(MPI a, MPI b, MPI input, ELG_public_key *pkey )
{
int rc;
MPI t1;
MPI t2;
MPI base[4];
MPI exp[4];
if( !(mpi_cmp_ui( a, 0 ) > 0 && mpi_cmp( a, pkey->p ) < 0) )
return 0; /* assertion 0 < a < p failed */
t1 = mpi_alloc( mpi_get_nlimbs(a) );
t2 = mpi_alloc( mpi_get_nlimbs(a) );
#if 0
/* t1 = (y^a mod p) * (a^b mod p) mod p */
mpi_powm( t1, pkey->y, a, pkey->p );
mpi_powm( t2, a, b, pkey->p );
mpi_mulm( t1, t1, t2, pkey->p );
/* t2 = g ^ input mod p */
mpi_powm( t2, pkey->g, input, pkey->p );
rc = !mpi_cmp( t1, t2 );
#elif 0
/* t1 = (y^a mod p) * (a^b mod p) mod p */
base[0] = pkey->y; exp[0] = a;
base[1] = a; exp[1] = b;
base[2] = NULL; exp[2] = NULL;
mpi_mulpowm( t1, base, exp, pkey->p );
/* t2 = g ^ input mod p */
mpi_powm( t2, pkey->g, input, pkey->p );
rc = !mpi_cmp( t1, t2 );
#else
/* t1 = g ^ - input * y ^ a * a ^ b mod p */
mpi_invm(t2, pkey->g, pkey->p );
base[0] = t2 ; exp[0] = input;
base[1] = pkey->y; exp[1] = a;
base[2] = a; exp[2] = b;
base[3] = NULL; exp[3] = NULL;
mpi_mulpowm( t1, base, exp, pkey->p );
rc = !mpi_cmp_ui( t1, 1 );
#endif
mpi_free(t1);
mpi_free(t2);
return rc;
}
/*********************************************
************** interface ******************
*********************************************/
int
elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
{
ELG_secret_key sk;
if( !is_ELGAMAL(algo) )
return G10ERR_PUBKEY_ALGO;
generate( &sk, nbits, retfactors );
skey[0] = sk.p;
skey[1] = sk.g;
skey[2] = sk.y;
skey[3] = sk.x;
return 0;
}
int
elg_check_secret_key( int algo, MPI *skey )
{
ELG_secret_key sk;
if( !is_ELGAMAL(algo) )
return G10ERR_PUBKEY_ALGO;
if( !skey[0] || !skey[1] || !skey[2] || !skey[3] )
return G10ERR_BAD_MPI;
sk.p = skey[0];
sk.g = skey[1];
sk.y = skey[2];
sk.x = skey[3];
if( !check_secret_key( &sk ) )
return G10ERR_BAD_SECKEY;
return 0;
}
int
elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
{
ELG_public_key pk;
if( !is_ELGAMAL(algo) )
return G10ERR_PUBKEY_ALGO;
if( !data || !pkey[0] || !pkey[1] || !pkey[2] )
return G10ERR_BAD_MPI;
pk.p = pkey[0];
pk.g = pkey[1];
pk.y = pkey[2];
resarr[0] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
resarr[1] = mpi_alloc( mpi_get_nlimbs( pk.p ) );
encrypt( resarr[0], resarr[1], data, &pk );
return 0;
}
int
elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
{
ELG_secret_key sk;
if( !is_ELGAMAL(algo) )
return G10ERR_PUBKEY_ALGO;
if( !data[0] || !data[1]
|| !skey[0] || !skey[1] || !skey[2] || !skey[3] )
return G10ERR_BAD_MPI;
sk.p = skey[0];
sk.g = skey[1];
sk.y = skey[2];
sk.x = skey[3];
*result = mpi_alloc_secure( mpi_get_nlimbs( sk.p ) );
decrypt( *result, data[0], data[1], &sk );
return 0;
}
int
elg_sign( int algo, MPI *resarr, MPI data, MPI *skey )
{
ELG_secret_key sk;
if( !is_ELGAMAL(algo) )
return G10ERR_PUBKEY_ALGO;
if( !data || !skey[0] || !skey[1] || !skey[2] || !skey[3] )
return G10ERR_BAD_MPI;
sk.p = skey[0];
sk.g = skey[1];
sk.y = skey[2];
sk.x = skey[3];
resarr[0] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
resarr[1] = mpi_alloc( mpi_get_nlimbs( sk.p ) );
sign( resarr[0], resarr[1], data, &sk );
return 0;
}
int
elg_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI) UNUSED, void *opaquev UNUSED)
{
ELG_public_key pk;
if( !is_ELGAMAL(algo) )
return G10ERR_PUBKEY_ALGO;
if( !data[0] || !data[1] || !hash
|| !pkey[0] || !pkey[1] || !pkey[2] )
return G10ERR_BAD_MPI;
pk.p = pkey[0];
pk.g = pkey[1];
pk.y = pkey[2];
if( !verify( data[0], data[1], hash, &pk ) )
return G10ERR_BAD_SIGN;
return 0;
}
unsigned
elg_get_nbits( int algo, MPI *pkey )
{
if( !is_ELGAMAL(algo) )
return 0;
return mpi_get_nbits( pkey[0] );
}
/****************
* Return some information about the algorithm. We need algo here to
* distinguish different flavors of the algorithm.
* Returns: A pointer to string describing the algorithm or NULL if
* the ALGO is invalid.
* Usage: Bit 0 set : allows signing
* 1 set : allows encryption
* NOTE: This function allows signing also for ELG-E, which is not
* okay but a bad hack to allow to work with old gpg keys. The real check
* is done in the gnupg ocde depending on the packet version.
*/
const char *
elg_get_info( int algo, int *npkey, int *nskey, int *nenc, int *nsig,
int *use )
{
*npkey = 3;
*nskey = 4;
*nenc = 2;
*nsig = 2;
switch( algo ) {
case PUBKEY_ALGO_ELGAMAL:
*use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC;
return "ELG";
case PUBKEY_ALGO_ELGAMAL_E:
*use = PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC;
return "ELG-E";
default: *use = 0; return NULL;
}
}
+35
View File
@@ -0,0 +1,35 @@
/* elgamal.h
* Copyright (C) 1998 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG 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.
*
* GnuPG 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_ELGAMAL_H
#define G10_ELGAMAL_H
int elg_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors );
int elg_check_secret_key( int algo, MPI *skey );
int elg_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey );
int elg_decrypt( int algo, MPI *result, MPI *data, MPI *skey );
int elg_sign( int algo, MPI *resarr, MPI data, MPI *skey );
int elg_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int (*cmp)(void *, MPI), void *opaquev );
unsigned elg_get_nbits( int algo, MPI *pkey );
const char *elg_get_info( int algo, int *npkey, int *nskey,
int *nenc, int *nsig, int *use );
#endif /*G10_ELGAMAL_H*/
+1081
View File
File diff suppressed because it is too large Load Diff
+79
View File
@@ -0,0 +1,79 @@
/* Dynamic fetching of X.509 CRLs
* Copyright (C) 2002 Stephane Laroche <stephane.laroche@colubris.com>
* Copyright (C) 2002-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* 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: fetch.h,v 1.6 2005/11/25 10:08:00 as Exp $
*/
#include "x509.h"
#define FETCH_CMD_TIMEOUT 10 /* seconds */
struct ocsp_location; /* forward declaration of ocsp_location defined in ocsp.h */
typedef enum {
FETCH_GET = 1,
FETCH_POST = 2
} fetch_request_t;
typedef struct fetch_req fetch_req_t;
struct fetch_req {
fetch_req_t *next;
time_t installed;
int trials;
chunk_t issuer;
chunk_t authKeyID;
chunk_t authKeySerialNumber;
generalName_t *distributionPoints;
};
#ifdef THREADS
extern void lock_crl_list(const char *who);
extern void unlock_crl_list(const char *who);
extern void lock_ocsp_cache(const char *who);
extern void unlock_ocsp_cache(const char *who);
extern void lock_ca_info_list(const char *who);
extern void unlock_ca_info_list(const char *who);
extern void lock_authcert_list(const char *who);
extern void unlock_authcert_list(const char *who);
extern void lock_certs_and_keys(const char *who);
extern void unlock_certs_and_keys(const char *who);
extern void wake_fetch_thread(const char *who);
#else
#define lock_crl_list(who) /* do nothing */
#define unlock_crl_list(who) /* do nothing */
#define lock_ocsp_cache(who) /* do nothing */
#define unlock_ocsp_cache(who) /* do nothing */
#define lock_ca_info_list(who) /* do nothing */
#define unlock_ca_info_list(who) /* do nothing */
#define lock_authcert_list(who) /* do nothing */
#define unlock_authcert_list(who) /* do nothing */
#define lock_certs_and_keys(who) /* do nothing */
#define unlock_certs_and_keys(who) /* do nothing */
#define wake_fetch_thread(who) /* do nothing */
#endif
extern void init_fetch(void);
extern void free_crl_fetch(void);
extern void free_ocsp_fetch(void);
extern void add_distribution_points(const generalName_t *newPoints
, generalName_t **distributionPoints);
extern fetch_req_t* build_crl_fetch_request(chunk_t issuer, chunk_t authKeySerialNumber
, chunk_t authKeyID, const generalName_t *gn);
extern void add_crl_fetch_request(fetch_req_t *req);
extern void add_ocsp_fetch_request(struct ocsp_location *location, chunk_t serialNumber);
extern void list_distribution_points(const generalName_t *gn);
extern void list_crl_fetch_requests(bool utc);
extern void list_ocsp_fetch_requests(bool utc);
extern size_t write_buffer(void *ptr, size_t size, size_t nmemb, void *data);
+462
View File
@@ -0,0 +1,462 @@
/* Implement policy groups-style control files (aka "foodgroups")
* Copyright (C) 2002 D. Hugh Redelmeier.
*
* 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: foodgroups.c,v 1.2 2004/04/01 18:28:32 as Exp $
*/
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/queue.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "connections.h"
#include "foodgroups.h"
#include "kernel.h"
#include "lex.h"
#include "log.h"
#include "whack.h"
/* Food group config files are found in directory fg_path */
#ifndef POLICYGROUPSDIR
#define POLICYGROUPSDIR "/etc/ipsec.d/policies"
#endif
const char *policygroups_dir = POLICYGROUPSDIR;
static char *fg_path = NULL;
static size_t fg_path_space = 0;
/* Groups is a list of connections that are policy groups.
* The list is updated as group connections are added and deleted.
*/
struct fg_groups {
struct fg_groups *next;
struct connection *connection;
};
static struct fg_groups *groups = NULL;
/* Targets is a list of pairs: subnet and its policy group.
* This list is bulk-updated on whack --listen and
* incrementally updated when group connections are deleted.
*
* It is ordered by source subnet, and if those are equal, then target subnet.
* A subnet is compared by comparing the network, and if those are equal,
* comparing the mask.
*/
struct fg_targets {
struct fg_targets *next;
struct fg_groups *group;
ip_subnet subnet;
char *name; /* name of instance of group conn */
};
static struct fg_targets *targets = NULL;
struct fg_targets *new_targets;
/* ipcmp compares the two ip_address values a and b.
* It returns -1, 0, or +1 if a is, respectively,
* less than, equal to, or greater than b.
*/
static int
ipcmp(ip_address *a, ip_address *b)
{
if (addrtypeof(a) != addrtypeof(b))
{
return addrtypeof(a) < addrtypeof(b)? -1 : 1;
}
else if (sameaddr(a, b))
{
return 0;
}
else
{
const struct sockaddr *sa = sockaddrof(a)
, *sb = sockaddrof(b);
passert(addrtypeof(a) == AF_INET); /* not yet implemented IPv6 version :-( */
return (ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr)
< ntohl(((const struct sockaddr_in *)sb)->sin_addr.s_addr))
? -1 : 1;
}
}
/* subnetcmp compares the two ip_subnet values a and b.
* It returns -1, 0, or +1 if a is, respectively,
* less than, equal to, or greater than b.
*/
static int
subnetcmp(const ip_subnet *a, const ip_subnet *b)
{
ip_address neta, maska, netb, maskb;
int r;
networkof(a, &neta);
maskof(a, &maska);
networkof(b, &netb);
maskof(b, &maskb);
r = ipcmp(&neta, &netb);
if (r == 0)
r = ipcmp(&maska, &maskb);
return r;
}
static void
read_foodgroup(struct fg_groups *g)
{
const char *fgn = g->connection->name;
const ip_subnet *lsn = &g->connection->spd.this.client;
size_t plen = strlen(policygroups_dir) + 1 + strlen(fgn) + 1;
struct file_lex_position flp_space;
if (plen > fg_path_space)
{
pfreeany(fg_path);
fg_path_space = plen + 10;
fg_path = alloc_bytes(fg_path_space, "policy group path");
}
snprintf(fg_path, fg_path_space, "%s/%s", policygroups_dir, fgn);
if (!lexopen(&flp_space, fg_path, TRUE))
{
DBG(DBG_CONTROL, DBG_log("no group file \"%s\"", fg_path));
}
else
{
plog("loading group \"%s\"", fg_path);
for (;;)
{
switch (flp->bdry)
{
case B_none:
{
/* !!! this test is not sufficient for distinguishing address families.
* We need a notation to specify that a FQDN is to be resolved to IPv6.
*/
const struct af_info *afi = strchr(tok, ':') == NULL
? &af_inet4_info: &af_inet6_info;
ip_subnet sn;
err_t ugh;
if (strchr(tok, '/') == NULL)
{
/* no /, so treat as /32 or V6 equivalent */
ip_address t;
ugh = ttoaddr(tok, 0, afi->af, &t);
if (ugh == NULL)
ugh = addrtosubnet(&t, &sn);
}
else
{
ugh = ttosubnet(tok, 0, afi->af, &sn);
}
if (ugh != NULL)
{
loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s \"%s\""
, flp->filename, flp->lino, ugh, tok);
}
else if (afi->af != AF_INET)
{
loglog(RC_LOG_SERIOUS
, "\"%s\" line %d: unsupported Address Family \"%s\""
, flp->filename, flp->lino, tok);
}
else
{
/* Find where new entry ought to go in new_targets. */
struct fg_targets **pp;
int r;
for (pp = &new_targets; ; pp = &(*pp)->next)
{
if (*pp == NULL)
{
r = -1; /* end of list is infinite */
break;
}
r = subnetcmp(lsn, &(*pp)->group->connection->spd.this.client);
if (r == 0)
r = subnetcmp(&sn, &(*pp)->subnet);
if (r <= 0)
break;
}
if (r == 0)
{
char source[SUBNETTOT_BUF];
subnettot(lsn, 0, source, sizeof(source));
loglog(RC_LOG_SERIOUS
, "\"%s\" line %d: subnet \"%s\", source %s, already \"%s\""
, flp->filename
, flp->lino
, tok
, source
, (*pp)->group->connection->name);
}
else
{
struct fg_targets *f = alloc_thing(struct fg_targets, "fg_target");
f->next = *pp;
f->group = g;
f->subnet = sn;
f->name = NULL;
*pp = f;
}
}
}
(void)shift(); /* next */
continue;
case B_record:
flp->bdry = B_none; /* eat the Record Boundary */
(void)shift(); /* get real first token */
continue;
case B_file:
break; /* done */
}
break; /* if we reach here, out of loop */
}
lexclose();
}
}
static void
free_targets(void)
{
while (targets != NULL)
{
struct fg_targets *t = targets;
targets = t->next;
pfreeany(t->name);
pfree(t);
}
}
void
load_groups(void)
{
passert(new_targets == NULL);
/* for each group, add config file targets into new_targets */
{
struct fg_groups *g;
for (g = groups; g != NULL; g = g->next)
if (oriented(*g->connection))
read_foodgroup(g);
}
/* dump new_targets */
DBG(DBG_CONTROL,
{
struct fg_targets *t;
for (t = new_targets; t != NULL; t = t->next)
{
char asource[SUBNETTOT_BUF];
char atarget[SUBNETTOT_BUF];
subnettot(&t->group->connection->spd.this.client
, 0, asource, sizeof(asource));
subnettot(&t->subnet, 0, atarget, sizeof(atarget));
DBG_log("%s->%s %s"
, asource, atarget
, t->group->connection->name);
}
});
/* determine and deal with differences between targets and new_targets.
* structured like a merge.
*/
{
struct fg_targets *op = targets
, *np = new_targets;
while (op != NULL && np != NULL)
{
int r = subnetcmp(&op->group->connection->spd.this.client
, &np->group->connection->spd.this.client);
if (r == 0)
r = subnetcmp(&op->subnet, &np->subnet);
if (r == 0 && op->group == np->group)
{
/* unchanged -- steal name & skip over */
np->name = op->name;
op->name = NULL;
op = op->next;
np = np->next;
}
else
{
/* note: following cases overlap! */
if (r <= 0)
{
remove_group_instance(op->group->connection, op->name);
op = op->next;
}
if (r >= 0)
{
np->name = add_group_instance(np->group->connection, &np->subnet);
np = np->next;
}
}
}
for (; op != NULL; op = op->next)
remove_group_instance(op->group->connection, op->name);
for (; np != NULL; np = np->next)
np->name = add_group_instance(np->group->connection, &np->subnet);
/* update: new_targets replaces targets */
free_targets();
targets = new_targets;
new_targets = NULL;
}
}
void
add_group(struct connection *c)
{
struct fg_groups *g = alloc_thing(struct fg_groups, "policy group");
g->next = groups;
groups = g;
g->connection = c;
}
static struct fg_groups *
find_group(const struct connection *c)
{
struct fg_groups *g;
for (g = groups; g != NULL && g->connection != c; g = g->next)
;
return g;
}
void
route_group(struct connection *c)
{
/* it makes no sense to route a connection that is ISAKMP-only */
if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy))
{
loglog(RC_ROUTE, "cannot route an ISAKMP-only group connection");
}
else
{
struct fg_groups *g = find_group(c);
struct fg_targets *t;
passert(g != NULL);
g->connection->policy |= POLICY_GROUTED;
for (t = targets; t != NULL; t = t->next)
{
if (t->group == g)
{
struct connection *ci = con_by_name(t->name, FALSE);
if (ci != NULL)
{
set_cur_connection(ci);
if (!trap_connection(ci))
whack_log(RC_ROUTE, "could not route");
set_cur_connection(c);
}
}
}
}
}
void
unroute_group(struct connection *c)
{
struct fg_groups *g = find_group(c);
struct fg_targets *t;
passert(g != NULL);
g->connection->policy &= ~POLICY_GROUTED;
for (t = targets; t != NULL; t = t->next)
{
if (t->group == g)
{
struct connection *ci = con_by_name(t->name, FALSE);
if (ci != NULL)
{
set_cur_connection(ci);
unroute_connection(ci);
set_cur_connection(c);
}
}
}
}
void
delete_group(const struct connection *c)
{
struct fg_groups *g;
/* find and remove from groups */
{
struct fg_groups **pp;
for (pp = &groups; (g = *pp)->connection != c; pp = &(*pp)->next)
;
*pp = g->next;
}
/* find and remove from targets */
{
struct fg_targets **pp;
for (pp = &targets; *pp != NULL; )
{
struct fg_targets *t = *pp;
if (t->group == g)
{
*pp = t->next;
remove_group_instance(t->group->connection, t->name);
pfree(t);
/* pp is ready for next iteration */
}
else
{
pp = &t->next;
}
}
}
pfree(g);
}
+24
View File
@@ -0,0 +1,24 @@
/* Implement policygroups-style control files (aka "foodgroups")
* Copyright (C) 2002 D. Hugh Redelmeier.
*
* 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: foodgroups.h,v 1.1 2004/03/15 20:35:28 as Exp $
*/
struct connection; /* forward declaration */
extern void add_group(struct connection *c);
extern void route_group(struct connection *c);
extern void unroute_group(struct connection *c);
extern void delete_group(const struct connection *c);
extern const char *policygroups_dir;
extern void load_groups(void);
+283
View File
@@ -0,0 +1,283 @@
/* Routines to make gcrypt routines feel at home in Pluto.
* Copyright (C) 1999 D. Hugh Redelmeier.
*
* 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: gcryptfix.c,v 1.1 2004/03/15 20:35:28 as Exp $
*/
#include <stdlib.h>
#include <gmp.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "rnd.h"
#include "gcryptfix.h" /* includes <gmp.h> "defs.h" "rnd.h" */
MPI
mpi_alloc( unsigned nlimbs UNUSED )
{
MPI n = alloc_bytes(sizeof *n, "mpi_alloc");
mpz_init(n);
return n;
}
MPI
mpi_alloc_secure( unsigned nlimbs )
{
return mpi_alloc(nlimbs);
}
MPI
mpi_alloc_set_ui( unsigned long u)
{
MPI n = alloc_bytes(sizeof *n, "mpi_copy");
mpz_init_set_ui(n, u);
return n;
}
MPI
mpi_copy( MPI a )
{
MPI n = alloc_bytes(sizeof *n, "mpi_copy");
mpz_init_set(n, a);
return n;
}
void
mpi_free( MPI a )
{
mpz_clear(a);
pfree(a);
}
int
mpi_divisible_ui(MPI dividend, ulong divisor )
{
ulong rem;
mpz_t remtoo;
mpz_init(remtoo);
rem = mpz_mod_ui(remtoo, dividend, divisor);
mpz_clear(remtoo);
return rem == 0;
}
unsigned
mpi_trailing_zeros( MPI a )
{
return mpz_scan1(a, 0);
}
unsigned
mpi_get_nbits( MPI a )
{
return mpz_sizeinbase(a, 2);
}
int
mpi_test_bit( MPI a, unsigned n )
{
/* inspired by gmp/mpz/clrbit.c */
mp_size_t li = n / mp_bits_per_limb;
if (li >= a->_mp_size)
return 0;
return (a->_mp_d[li] & ((mp_limb_t) 1 << (n % mp_bits_per_limb))) != 0;
}
void
mpi_set_bit( MPI a, unsigned n )
{
mpz_setbit(a, n);
}
void
mpi_clear_bit( MPI a, unsigned n )
{
mpz_clrbit(a, n);
}
void
mpi_clear_highbit( MPI a, unsigned n )
{
/* This seems whacky, but what do I know. */
mpz_fdiv_r_2exp(a, a, n);
}
void
mpi_set_highbit( MPI a, unsigned n )
{
/* This seems whacky, but what do I know. */
mpz_fdiv_r_2exp(a, a, n+1);
mpz_setbit(a, n);
}
void
mpi_set_buffer( MPI a, const u_char *buffer, unsigned nbytes, int sign )
{
/* this is a lot like n_to_mpz */
size_t i;
passert(sign == 0); /* we won't hit any negative numbers */
mpz_init_set_ui(a, 0);
for (i = 0; i != nbytes; i++)
{
mpz_mul_ui(a, a, 1 << BITS_PER_BYTE);
mpz_add_ui(a, a, buffer[i]);
}
}
u_char *
get_random_bits(size_t nbits, int level UNUSED, int secure UNUSED)
{
size_t nbytes = (nbits+7)/8;
u_char *b = alloc_bytes(nbytes, "random bytes");
get_rnd_bytes(b, nbytes);
return b;
}
/**************** from gnupg-1.0.0/mpi/mpi-mpow.c
* RES = (BASE[0] ^ EXP[0]) * (BASE[1] ^ EXP[1]) * ... * mod M
*/
#define barrett_mulm( w, u, v, m, y, k, r1, r2 ) mpi_mulm( (w), (u), (v), (m) )
static int
build_index( MPI *exparray, int k, int i, int t )
{
int j, bitno;
int index = 0;
bitno = t-i;
for(j=k-1; j >= 0; j-- ) {
index <<= 1;
if( mpi_test_bit( exparray[j], bitno ) )
index |= 1;
}
/*log_debug("t=%d i=%d index=%d\n", t, i, index );*/
return index;
}
void
mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI m)
{
int k; /* number of elements */
int t; /* bit size of largest exponent */
int i, j, idx;
MPI *G; /* table with precomputed values of size 2^k */
MPI tmp;
#ifdef USE_BARRETT
MPI barrett_y, barrett_r1, barrett_r2;
int barrett_k;
#endif
for(k=0; basearray[k]; k++ )
;
passert(k);
for(t=0, i=0; (tmp=exparray[i]); i++ ) {
/*log_mpidump("exp: ", tmp );*/
j = mpi_get_nbits(tmp);
if( j > t )
t = j;
}
/*log_mpidump("mod: ", m );*/
passert(i==k);
passert(t);
passert( k < 10 );
#ifdef PLUTO
m_alloc_ptrs_clear(G, 1<<k);
#else
G = m_alloc_clear( (1<<k) * sizeof *G );
#endif
#ifdef USE_BARRETT
barrett_y = init_barrett( m, &barrett_k, &barrett_r1, &barrett_r2 );
#endif
/* and calculate */
tmp = mpi_alloc( mpi_get_nlimbs(m)+1 );
mpi_set_ui( res, 1 );
for(i = 1; i <= t; i++ ) {
barrett_mulm(tmp, res, res, m, barrett_y, barrett_k,
barrett_r1, barrett_r2 );
idx = build_index( exparray, k, i, t );
passert( idx >= 0 && idx < (1<<k) );
if( !G[idx] ) {
if( !idx )
G[0] = mpi_alloc_set_ui( 1 );
else {
for(j=0; j < k; j++ ) {
if( (idx & (1<<j) ) ) {
if( !G[idx] )
G[idx] = mpi_copy( basearray[j] );
else
barrett_mulm( G[idx], G[idx], basearray[j],
m, barrett_y, barrett_k, barrett_r1, barrett_r2 );
}
}
if( !G[idx] )
G[idx] = mpi_alloc(0);
}
}
barrett_mulm(res, tmp, G[idx], m, barrett_y, barrett_k, barrett_r1, barrett_r2 );
}
/* cleanup */
mpi_free(tmp);
#ifdef USE_BARRETT
mpi_free(barrett_y);
mpi_free(barrett_r1);
mpi_free(barrett_r2);
#endif
for(i=0; i < (1<<k); i++ )
mpi_free(G[i]);
m_free(G);
}
void
log_mpidump( const char *text UNUSED, MPI a )
{
/* Print number in hex -- helpful to see if they match bytes.
* Humans are not going to do arithmetic with the large numbers!
* Much code adapted from mpz_to_n.
*/
u_char buf[8048]; /* this ought to be big enough */
size_t len = (mpz_sizeinbase(a, 16) + 1) / 2; /* bytes */
MP_INT temp1, temp2;
int i;
passert(len <= sizeof(buf));
mpz_init(&temp1);
mpz_init(&temp2);
mpz_set(&temp1, a);
for (i = len-1; i >= 0; i--)
{
buf[i] = mpz_mdivmod_ui(&temp2, NULL, &temp1, 1 << BITS_PER_BYTE);
mpz_set(&temp1, &temp2);
}
passert(mpz_sgn(&temp1) == 0); /* we must have done all the bits */
mpz_clear(&temp1);
mpz_clear(&temp2);
#ifdef DEBUG
DBG_dump(text, buf, len);
#endif /* DEBUG */
}
+111
View File
@@ -0,0 +1,111 @@
/* Definitions to make gcrypt routines feel at home in Pluto.
* Copyright (C) 1999 D. Hugh Redelmeier.
*
* 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: gcryptfix.h,v 1.1 2004/03/15 20:35:28 as Exp $
*/
#define DBG_CIPHER 1 /* some day we'll do this right */
/* Simulate MPI routines with gmp routines.
* gmp's MP_INT is a stuct; MPI's MPI is a pointer to an analogous struct.
* gmp's mpz_t is an array of one of these structs to enable magic pointer
* conversions to make the notation convenient (but confusing).
*/
typedef u_char byte;
typedef MP_INT *MPI;
#define BITS_PER_MPI_LIMB mp_bits_per_limb
extern MPI mpi_alloc( unsigned nlimbs );
extern MPI mpi_alloc_secure( unsigned nlimbs );
#define mpi_alloc_like(n) mpi_alloc(mpi_get_nlimbs(n))
extern MPI mpi_alloc_set_ui( unsigned long u);
#define mpi_set_ui(w, u) mpz_set_ui(w, u)
#define mpi_set(w, u) mpz_set(w, u)
extern void mpi_free( MPI a );
extern MPI mpi_copy( MPI a );
extern unsigned mpi_get_nbits( MPI a );
#define mpi_get_nlimbs(a) ((a)->_mp_alloc) /* dirty, but useless */
extern void mpi_set_buffer( MPI a, const u_char *buffer, unsigned nbytes, int sign );
extern unsigned mpi_trailing_zeros( MPI a );
extern int mpi_test_bit( MPI a, unsigned n );
extern void mpi_set_bit( MPI a, unsigned n );
extern void mpi_clear_bit( MPI a, unsigned n );
extern void mpi_clear_highbit( MPI a, unsigned n );
extern void mpi_set_highbit( MPI a, unsigned n );
#define mpi_cmp_ui(u, v) mpz_cmp_ui((u), (v))
#define mpi_cmp(u, v) mpz_cmp((u), (v))
#define mpi_is_neg(n) (mpz_sgn(n) < 0)
#define mpi_add(w, u, v) mpz_add((w), (u), (v))
#define mpi_add_ui(w, u, v) mpz_add_ui((w), (u), (v))
#define mpi_sub_ui(w, u, v) mpz_sub_ui((w), (u), (v))
#define mpi_subm( w, u, v, m) { mpz_sub( (w), (u), (v)) ; mpz_fdiv_r((w), (w), (m)); }
#define mpi_mul( w, u, v) mpz_mul( (w), (u), (v))
#define mpi_mul_ui( w, u, v) mpz_mul_ui( (w), (u), (v))
#define mpi_mulm( w, u, v, m) { mpz_mul( (w), (u), (v)) ; mpz_fdiv_r((w), (w), (m)); }
#define mpi_fdiv_q(quot, dividend, divisor) mpz_fdiv_q((quot), (dividend), (divisor))
#define mpi_fdiv_r( rem, dividend, divisor ) mpz_fdiv_r( (rem), (dividend), (divisor) )
#define mpi_fdiv_r_ui( rem, dividend, divisor ) mpz_fdiv_r_ui( (rem), (dividend), (divisor) )
#define mpi_tdiv_q_2exp( w, u, count ) mpz_tdiv_q_2exp( (w), (u), (count) )
extern int mpi_divisible_ui(MPI dividend, ulong divisor );
#define mpi_powm( res, base, exp, mod) mpz_powm( res, base, exp, mod)
extern void mpi_mulpowm( MPI res, MPI *basearray, MPI *exparray, MPI mod);
#define mpi_gcd( g, a, b ) ( mpz_gcd( (g), (a), (b) ), !mpi_cmp_ui( (g), 1))
#define mpi_invm( x, a, n ) mpz_invert( (x), (a), (n) )
#ifdef DEBUG
# define log_debug(f...) DBG_log(f)
#else
# define log_debug(f...) do ; while (0) /* do nothing, carefully */
#endif
#define log_fatal(f...) exit_log(f) /* overreaction? */
extern void log_mpidump( const char *text, MPI a );
#define assert(p) passert(p)
#define BUG() passert(FALSE)
#define m_alloc_ptrs_clear(pp, n) { \
int c = (n); \
(pp) = alloc_bytes((n) * sizeof(*(pp)), "m_alloc_ptrs_clear"); \
while (c > 0) (pp)[--c] = NULL; \
}
extern u_char *get_random_bits(size_t nbits, int level, int secure);
#define m_alloc(sz) alloc_bytes((sz), "m_alloc") /* not initialized */
#define m_free(n) pfree(n) /* always freeing something from get_random_bits */
/* declarations from gnupg-1.0.0/include/cipher.h */
/*-- primegen.c --*/
MPI generate_secret_prime( unsigned nbits );
MPI generate_public_prime( unsigned nbits );
MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
MPI g, MPI **factors );
#define PUBKEY_ALGO_ELGAMAL_E 16 /* encrypt only ElGamal (but not for v3)*/
#define PUBKEY_ALGO_DSA 17
#define PUBKEY_ALGO_ELGAMAL 20 /* sign and encrypt elgamal */
#define is_ELGAMAL(a) ((a)==PUBKEY_ALGO_ELGAMAL || (a)==PUBKEY_ALGO_ELGAMAL_E)
#define PUBKEY_USAGE_SIG 1 /* key is good for signatures */
#define PUBKEY_USAGE_ENC 2 /* key is good for encryption */
/* from gnupg-1.0.0/include/errors.h */
#define G10ERR_PUBKEY_ALGO 4 /* Unknown pubkey algorithm */
#define G10ERR_BAD_SECKEY 7 /* Bad secret key */
#define G10ERR_BAD_SIGN 8 /* Bad signature */
#define G10ERR_BAD_MPI 30
/*-- smallprime.c --*/
extern ushort small_prime_numbers[];
+509
View File
@@ -0,0 +1,509 @@
/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
* Copyright (C) 1999-2001 D. Hugh Redelmeier
*
* 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: id.c,v 1.4 2005/08/15 20:07:08 as Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#ifndef HOST_NAME_MAX /* POSIX 1003.1-2001 says <unistd.h> defines this */
# define HOST_NAME_MAX 255 /* upper bound, according to SUSv2 */
#endif
#include <sys/queue.h>
#include <freeswan.h>
#include <freeswan/ipsec_policy.h>
#include "constants.h"
#include "defs.h"
#include "id.h"
#include "log.h"
#include "connections.h"
#include "packet.h"
#include "whack.h"
const struct id empty_id; /* ID_NONE */
enum myid_state myid_state = MYID_UNKNOWN;
struct id myids[MYID_SPECIFIED+1]; /* %myid */
char *myid_str[MYID_SPECIFIED+1]; /* string form of IDs */
/* initialize id module
* Fills in myid from environment variable IPSECmyid or defaultrouteaddr
*/
void
init_id(void)
{
passert(empty_id.kind == ID_NONE);
myid_state = MYID_UNKNOWN;
{
enum myid_state s;
for (s = MYID_UNKNOWN; s <= MYID_SPECIFIED; s++)
{
myids[s] = empty_id;
myid_str[s] = NULL;
}
}
set_myid(MYID_SPECIFIED, getenv("IPSECmyid"));
set_myid(MYID_IP, getenv("defaultrouteaddr"));
set_myFQDN();
}
static void
calc_myid_str(enum myid_state s)
{
/* preformat the ID name */
char buf[BUF_LEN];
idtoa(&myids[s], buf, BUF_LEN);
replace(myid_str[s], clone_str(buf, "myid string"));
}
void
set_myid(enum myid_state s, char *idstr)
{
if (idstr != NULL)
{
struct id id;
err_t ugh = atoid(idstr, &id, FALSE);
if (ugh != NULL)
{
loglog(RC_BADID, "myid malformed: %s \"%s\"", ugh, idstr);
}
else
{
free_id_content(&myids[s]);
unshare_id_content(&id);
myids[s] = id;
if (s == MYID_SPECIFIED)
myid_state = MYID_SPECIFIED;
calc_myid_str(s);
}
}
}
void
set_myFQDN(void)
{
char FQDN[HOST_NAME_MAX + 1];
int r = gethostname(FQDN, sizeof(FQDN));
free_id_content(&myids[MYID_HOSTNAME]);
myids[MYID_HOSTNAME] = empty_id;
if (r != 0)
{
log_errno((e, "gethostname() failed in set_myFQDN"));
}
else
{
FQDN[sizeof(FQDN) - 1] = '\0'; /* insurance */
{
size_t len = strlen(FQDN);
if (len > 0 && FQDN[len-1] == '.')
{
/* nuke trailing . */
FQDN[len-1]='\0';
}
}
if (!strcaseeq(FQDN, "localhost.localdomain"))
{
clonetochunk(myids[MYID_HOSTNAME].name, FQDN, strlen(FQDN), "my FQDN");
myids[MYID_HOSTNAME].kind = ID_FQDN;
calc_myid_str(MYID_HOSTNAME);
}
}
}
void
show_myid_status(void)
{
char idstr[BUF_LEN];
(void)idtoa(&myids[myid_state], idstr, sizeof(idstr));
whack_log(RC_COMMENT, "%%myid = %s", idstr);
}
/* Convert textual form of id into a (temporary) struct id.
* Note that if the id is to be kept, unshare_id_content will be necessary.
*/
err_t
atoid(char *src, struct id *id, bool myid_ok)
{
err_t ugh = NULL;
*id = empty_id;
if (myid_ok && streq("%myid", src))
{
id->kind = ID_MYID;
}
else if (strchr(src, '=') != NULL)
{
/* we interpret this as an ASCII X.501 ID_DER_ASN1_DN */
id->kind = ID_DER_ASN1_DN;
id->name.ptr = temporary_cyclic_buffer(); /* assign temporary buffer */
id->name.len = 0;
/* convert from LDAP style or openssl x509 -subject style to ASN.1 DN
* discard optional @ character in front of DN
*/
ugh = atodn((*src == '@')?src+1:src, &id->name);
}
else if (strchr(src, '@') == NULL)
{
if (streq(src, "%any") || streq(src, "0.0.0.0"))
{
/* any ID will be accepted */
id->kind = ID_NONE;
}
else
{
/* !!! this test is not sufficient for distinguishing address families.
* We need a notation to specify that a FQDN is to be resolved to IPv6.
*/
const struct af_info *afi = strchr(src, ':') == NULL
? &af_inet4_info: &af_inet6_info;
id->kind = afi->id_addr;
ugh = ttoaddr(src, 0, afi->af, &id->ip_addr);
}
}
else
{
if (*src == '@')
{
if (*(src+1) == '#')
{
/* if there is a second specifier (#) on the line
* we interprete this as ID_KEY_ID
*/
id->kind = ID_KEY_ID;
id->name.ptr = src;
/* discard @~, convert from hex to bin */
ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
}
else if (*(src+1) == '~')
{
/* if there is a second specifier (~) on the line
* we interprete this as a binary ID_DER_ASN1_DN
*/
id->kind = ID_DER_ASN1_DN;
id->name.ptr = src;
/* discard @~, convert from hex to bin */
ugh = ttodata(src+2, 0, 16, id->name.ptr, strlen(src), &id->name.len);
}
else
{
id->kind = ID_FQDN;
id->name.ptr = src+1; /* discard @ */
id->name.len = strlen(src)-1;
}
}
else
{
/* We leave in @, as per DOI 4.6.2.4
* (but DNS wants . instead).
*/
id->kind = ID_USER_FQDN;
id->name.ptr = src;
id->name.len = strlen(src);
}
}
return ugh;
}
/*
* Converts a binary key ID into hexadecimal format
*/
int
keyidtoa(char *dst, size_t dstlen, chunk_t keyid)
{
int n = datatot(keyid.ptr, keyid.len, 'x', dst, dstlen);
return (((size_t)n < dstlen)? n : dstlen) - 1;
}
void
iptoid(const ip_address *ip, struct id *id)
{
*id = empty_id;
switch (addrtypeof(ip))
{
case AF_INET:
id->kind = ID_IPV4_ADDR;
break;
case AF_INET6:
id->kind = ID_IPV6_ADDR;
break;
default:
bad_case(addrtypeof(ip));
}
id->ip_addr = *ip;
}
int
idtoa(const struct id *id, char *dst, size_t dstlen)
{
int n;
id = resolve_myid(id);
switch (id->kind)
{
case ID_NONE:
n = snprintf(dst, dstlen, "(none)");
break;
case ID_IPV4_ADDR:
case ID_IPV6_ADDR:
n = (int)addrtot(&id->ip_addr, 0, dst, dstlen) - 1;
break;
case ID_FQDN:
n = snprintf(dst, dstlen, "@%.*s", (int)id->name.len, id->name.ptr);
break;
case ID_USER_FQDN:
n = snprintf(dst, dstlen, "%.*s", (int)id->name.len, id->name.ptr);
break;
case ID_DER_ASN1_DN:
n = dntoa(dst, dstlen, id->name);
break;
case ID_KEY_ID:
n = keyidtoa(dst, dstlen, id->name);
break;
default:
n = snprintf(dst, dstlen, "unknown id kind %d", id->kind);
break;
}
/* "Sanitize" string so that log isn't endangered:
* replace unprintable characters with '?'.
*/
if (n > 0)
{
for ( ; *dst != '\0'; dst++)
if (!isprint(*dst))
*dst = '?';
}
return n;
}
/* Replace the shell metacharacters ', \, ", `, and $ in a character string
* by escape sequences consisting of their octal values
*/
void
escape_metachar(const char *src, char *dst, size_t dstlen)
{
while (*src != '\0' && dstlen > 4)
{
switch (*src)
{
case '\'':
case '\\':
case '"':
case '`':
case '$':
sprintf(dst,"\\%s%o", (*src < 64)?"0":"", *src);
dst += 4;
dstlen -= 4;
break;
default:
*dst++ = *src;
dstlen--;
}
src++;
}
*dst = '\0';
}
/* Make private copy of string in struct id.
* This is needed if the result of atoid is to be kept.
*/
void
unshare_id_content(struct id *id)
{
switch (id->kind)
{
case ID_FQDN:
case ID_USER_FQDN:
case ID_DER_ASN1_DN:
case ID_KEY_ID:
id->name.ptr = clone_bytes(id->name.ptr, id->name.len, "keep id name");
break;
case ID_MYID:
case ID_NONE:
case ID_IPV4_ADDR:
case ID_IPV6_ADDR:
break;
default:
bad_case(id->kind);
}
}
void
free_id_content(struct id *id)
{
switch (id->kind)
{
case ID_FQDN:
case ID_USER_FQDN:
case ID_DER_ASN1_DN:
case ID_KEY_ID:
freeanychunk(id->name);
break;
case ID_MYID:
case ID_NONE:
case ID_IPV4_ADDR:
case ID_IPV6_ADDR:
break;
default:
bad_case(id->kind);
}
}
/* compare two struct id values */
bool
same_id(const struct id *a, const struct id *b)
{
a = resolve_myid(a);
b = resolve_myid(b);
if (a->kind != b->kind)
return FALSE;
switch (a->kind)
{
case ID_NONE:
return TRUE; /* kind of vacuous */
case ID_IPV4_ADDR:
case ID_IPV6_ADDR:
return sameaddr(&a->ip_addr, &b->ip_addr);
case ID_FQDN:
case ID_USER_FQDN:
/* assumptions:
* - case should be ignored
* - trailing "." should be ignored (even if the only character?)
*/
{
size_t al = a->name.len
, bl = b->name.len;
while (al > 0 && a->name.ptr[al - 1] == '.')
al--;
while (bl > 0 && b->name.ptr[bl - 1] == '.')
bl--;
return al == bl
&& strncasecmp(a->name.ptr, b->name.ptr, al) == 0;
}
case ID_DER_ASN1_DN:
return same_dn(a->name, b->name);
case ID_KEY_ID:
return a->name.len == b->name.len
&& memcmp(a->name.ptr, b->name.ptr, a->name.len) == 0;
default:
bad_case(a->kind);
}
return FALSE;
}
/* compare two struct id values, DNs can contain wildcards */
bool
match_id(const struct id *a, const struct id *b, int *wildcards)
{
if (b->kind == ID_NONE)
{
*wildcards = MAX_WILDCARDS;
return TRUE;
}
if (a->kind != b->kind)
return FALSE;
if (a->kind == ID_DER_ASN1_DN)
return match_dn(a->name, b->name, wildcards);
else
{
*wildcards = 0;
return same_id(a, b);
}
}
/* count the numer of wildcards in an id */
int
id_count_wildcards(const struct id *id)
{
switch (id->kind)
{
case ID_NONE:
return MAX_WILDCARDS;
case ID_DER_ASN1_DN:
return dn_count_wildcards(id->name);
default:
return 0;
}
}
/* build an ID payload
* Note: no memory is allocated for the body of the payload (tl->ptr).
* We assume it will end up being a pointer into a sufficiently
* stable datastructure. It only needs to last a short time.
*/
void
build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end)
{
const struct id *id = resolve_myid(&end->id);
zero(hd);
hd->isaiid_idtype = id->kind;
switch (id->kind)
{
case ID_NONE:
hd->isaiid_idtype = aftoinfo(addrtypeof(&end->host_addr))->id_addr;
tl->len = addrbytesptr(&end->host_addr
, (const unsigned char **)&tl->ptr); /* sets tl->ptr too */
break;
case ID_FQDN:
case ID_USER_FQDN:
case ID_DER_ASN1_DN:
case ID_KEY_ID:
*tl = id->name;
break;
case ID_IPV4_ADDR:
case ID_IPV6_ADDR:
tl->len = addrbytesptr(&id->ip_addr
, (const unsigned char **)&tl->ptr); /* sets tl->ptr too */
break;
default:
bad_case(id->kind);
}
}
/*
* Local Variables:
* c-basic-offset:4
* c-style: pluto
* End:
*/
+67
View File
@@ -0,0 +1,67 @@
/* identity representation, as in IKE ID Payloads (RFC 2407 DOI 4.6.2.1)
* Copyright (C) 1999-2001 D. Hugh Redelmeier
*
* 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: id.h,v 1.5 2005/08/15 20:07:08 as Exp $
*/
#ifndef _ID_H
#define _ID_H
#include "defs.h"
struct id {
int kind; /* ID_* value */
ip_address ip_addr; /* ID_IPV4_ADDR, ID_IPV6_ADDR */
chunk_t name; /* ID_FQDN, ID_USER_FQDN (with @) */
/* ID_KEY_ID, ID_DER_ASN_DN */
};
extern void init_id(void);
extern const struct id empty_id; /* ID_NONE */
enum myid_state {
MYID_UNKNOWN, /* not yet figured out */
MYID_HOSTNAME, /* our current hostname */
MYID_IP, /* our default IP address */
MYID_SPECIFIED /* as specified by ipsec.conf */
};
extern enum myid_state myid_state;
extern struct id myids[MYID_SPECIFIED+1]; /* %myid */
extern char *myid_str[MYID_SPECIFIED+1]; /* strings */
extern void set_myid(enum myid_state s, char *);
extern void show_myid_status(void);
#define resolve_myid(id) ((id)->kind == ID_MYID? &myids[myid_state] : (id))
extern void set_myFQDN(void);
extern err_t atoid(char *src, struct id *id, bool myid_ok);
extern int keyidtoa(char *dst, size_t dstlen, chunk_t keyid);
extern void iptoid(const ip_address *ip, struct id *id);
extern int idtoa(const struct id *id, char *dst, size_t dstlen);
#define IDTOA_BUF 512
extern void escape_metachar(const char *src, char *dst, size_t dstlen);
struct end; /* forward declaration of tag (defined in connections.h) */
extern void unshare_id_content(struct id *id);
extern void free_id_content(struct id *id);
extern bool same_id(const struct id *a, const struct id *b);
#define MAX_WILDCARDS 15
extern bool match_id(const struct id *a, const struct id *b, int *wildcards);
extern int id_count_wildcards(const struct id *id);
#define id_is_ipaddr(id) ((id)->kind == ID_IPV4_ADDR || (id)->kind == ID_IPV6_ADDR)
struct isakmp_ipsec_id; /* forward declaration of tag (defined in packet.h) */
extern void
build_id_payload(struct isakmp_ipsec_id *hd, chunk_t *tl, struct end *end);
#endif /* _ID_H */
+459
View File
@@ -0,0 +1,459 @@
/* IKE modular algorithm handling interface
* Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
*
* 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: ike_alg.c,v 1.6 2004/09/17 21:29:50 as Exp $
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/queue.h>
#include <freeswan.h>
#include <freeswan/ipsec_policy.h>
#include "constants.h"
#include "defs.h"
#include "sha1.h"
#include "md5.h"
#include "crypto.h"
#include "state.h"
#include "packet.h"
#include "log.h"
#include "whack.h"
#include "spdb.h"
#include "alg_info.h"
#include "ike_alg.h"
#include "db_ops.h"
#include "connections.h"
#include "kernel.h"
#define return_on(var, val) do { var=val;goto return_out; } while(0);
/*
* IKE algorithm list handling - registration and lookup
*/
/* Modular IKE algorithm storage structure */
static struct ike_alg *ike_alg_base[IKE_ALG_MAX+1] = {NULL, NULL};
/*
* return ike_algo object by {type, id}
*/
static struct ike_alg *
ike_alg_find(u_int algo_type, u_int algo_id, u_int keysize __attribute__((unused)))
{
struct ike_alg *e = ike_alg_base[algo_type];
while (e != NULL && algo_id > e->algo_id)
{
e = e->algo_next;
}
return (e != NULL && e->algo_id == algo_id) ? e : NULL;
}
/*
* "raw" ike_alg list adding function
*/
int
ike_alg_add(struct ike_alg* a)
{
if (a->algo_type > IKE_ALG_MAX)
{
plog("ike_alg: Not added, invalid algorithm type");
return -EINVAL;
}
if (ike_alg_find(a->algo_type, a->algo_id, 0) != NULL)
{
plog("ike_alg: Not added, algorithm already exists");
return -EEXIST;
}
{
struct ike_alg **ep = &ike_alg_base[a->algo_type];
struct ike_alg *e = *ep;
while (e != NULL && a->algo_id > e->algo_id)
{
ep = &e->algo_next;
e = *ep;
}
*ep = a;
a->algo_next = e;
return 0;
}
}
/*
* get IKE hash algorithm
*/
struct hash_desc *ike_alg_get_hasher(u_int alg)
{
return (struct hash_desc *) ike_alg_find(IKE_ALG_HASH, alg, 0);
}
/*
* get IKE encryption algorithm
*/
struct encrypt_desc *ike_alg_get_encrypter(u_int alg)
{
return (struct encrypt_desc *) ike_alg_find(IKE_ALG_ENCRYPT, alg, 0);
}
/*
* check if IKE hash algorithm is present
*/
bool
ike_alg_hash_present(u_int halg)
{
return ike_alg_get_hasher(halg) != NULL;
}
/*
* check if IKE encryption algorithm is present
*/
bool
ike_alg_enc_present(u_int ealg)
{
return ike_alg_get_encrypter(ealg) != NULL;
}
/*
* Validate and register IKE hash algorithm object
*/
int
ike_alg_register_hash(struct hash_desc *hash_desc)
{
const char *alg_name = NULL;
int ret = 0;
if (hash_desc->algo_id > OAKLEY_HASH_MAX)
{
plog ("ike_alg: hash alg=%d > max=%d"
, hash_desc->algo_id, OAKLEY_HASH_MAX);
return_on(ret,-EINVAL);
}
if (hash_desc->hash_ctx_size > sizeof (union hash_ctx))
{
plog ("ike_alg: hash alg=%d has ctx_size=%d > hash_ctx=%d"
, hash_desc->algo_id
, (int)hash_desc->hash_ctx_size
, (int)sizeof (union hash_ctx));
return_on(ret,-EOVERFLOW);
}
if (!(hash_desc->hash_init && hash_desc->hash_update && hash_desc->hash_final))
{
plog ("ike_alg: hash alg=%d needs hash_init(), hash_update() and hash_final()"
, hash_desc->algo_id);
return_on(ret,-EINVAL);
}
alg_name = enum_name(&oakley_hash_names, hash_desc->algo_id);
if (!alg_name)
{
plog ("ike_alg: hash alg=%d not found in constants.c:oakley_hash_names"
, hash_desc->algo_id);
alg_name = "<NULL>";
}
return_out:
if (ret == 0)
ret = ike_alg_add((struct ike_alg *)hash_desc);
plog("ike_alg: Activating %s hash: %s"
,alg_name, ret == 0 ? "Ok" : "FAILED");
return ret;
}
/*
* Validate and register IKE encryption algorithm object
*/
int
ike_alg_register_enc(struct encrypt_desc *enc_desc)
{
int ret = ike_alg_add((struct ike_alg *)enc_desc);
const char *alg_name = enum_name(&oakley_enc_names, enc_desc->algo_id);
char alg_number[20];
/* algorithm is not listed in oakley_enc_names */
if (alg_name == NULL)
{
snprintf(alg_number, sizeof(alg_number), "OAKLEY_ID_%d"
, enc_desc->algo_id);
alg_name = alg_number;
}
plog("ike_alg: Activating %s encryption: %s"
, alg_name, ret == 0 ? "Ok" : "FAILED");
return ret;
}
/*
* Get pfsgroup for this connection
*/
const struct oakley_group_desc *
ike_alg_pfsgroup(struct connection *c, lset_t policy)
{
const struct oakley_group_desc * ret = NULL;
if ((policy & POLICY_PFS)
&& c->alg_info_esp
&& c->alg_info_esp->esp_pfsgroup)
ret = lookup_group(c->alg_info_esp->esp_pfsgroup);
return ret;
}
/*
* Create an OAKLEY proposal based on alg_info and policy
*/
struct db_context *
ike_alg_db_new(struct alg_info_ike *ai , lset_t policy)
{
struct db_context *db_ctx = NULL;
struct ike_info *ike_info;
u_int ealg, halg, modp, eklen = 0;
struct encrypt_desc *enc_desc;
int i;
if (!ai)
{
whack_log(RC_LOG_SERIOUS, "no IKE algorithms "
"for this connection "
"(check ike algorithm string)");
goto fail;
}
policy &= POLICY_ID_AUTH_MASK;
db_ctx = db_prop_new(PROTO_ISAKMP, 8, 8 * 5);
/* for each group */
ALG_INFO_IKE_FOREACH(ai, ike_info, i)
{
ealg = ike_info->ike_ealg;
halg = ike_info->ike_halg;
modp = ike_info->ike_modp;
eklen= ike_info->ike_eklen;
if (!ike_alg_enc_present(ealg))
{
DBG_log("ike_alg: ike enc ealg=%d not present"
, ealg);
continue;
}
if (!ike_alg_hash_present(halg))
{
DBG_log("ike_alg: ike hash halg=%d not present"
, halg);
continue;
}
enc_desc = ike_alg_get_encrypter(ealg);
passert(enc_desc != NULL);
if (eklen
&& (eklen < enc_desc->keyminlen || eklen > enc_desc->keymaxlen))
{
DBG_log("ike_alg: ealg=%d (specified) keylen:%d, not valid min=%d, max=%d"
, ealg
, eklen
, enc_desc->keyminlen
, enc_desc->keymaxlen
);
continue;
}
if (policy & POLICY_RSASIG)
{
db_trans_add(db_ctx, KEY_IKE);
db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg);
db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg);
if (eklen)
db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, eklen);
db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_RSA_SIG);
db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp);
}
if (policy & POLICY_PSK)
{
db_trans_add(db_ctx, KEY_IKE);
db_attr_add_values(db_ctx, OAKLEY_ENCRYPTION_ALGORITHM, ealg);
db_attr_add_values(db_ctx, OAKLEY_HASH_ALGORITHM, halg);
if (ike_info->ike_eklen)
db_attr_add_values(db_ctx, OAKLEY_KEY_LENGTH, ike_info->ike_eklen);
db_attr_add_values(db_ctx, OAKLEY_AUTHENTICATION_METHOD, OAKLEY_PRESHARED_KEY);
db_attr_add_values(db_ctx, OAKLEY_GROUP_DESCRIPTION, modp);
}
}
fail:
return db_ctx;
}
/*
* Show registered IKE algorithms
*/
void
ike_alg_list(void)
{
u_int i;
struct ike_alg *a;
whack_log(RC_COMMENT, " ");
whack_log(RC_COMMENT, "List of registered IKE Encryption Algorithms:");
whack_log(RC_COMMENT, " ");
for (a = ike_alg_base[IKE_ALG_ENCRYPT]; a != NULL; a = a->algo_next)
{
struct encrypt_desc *desc = (struct encrypt_desc*)a;
whack_log(RC_COMMENT, "#%-5d %s, blocksize: %d, keylen: %d-%d-%d"
, a->algo_id
, enum_name(&oakley_enc_names, a->algo_id)
, (int)desc->enc_blocksize*BITS_PER_BYTE
, desc->keyminlen
, desc->keydeflen
, desc->keymaxlen
);
}
whack_log(RC_COMMENT, " ");
whack_log(RC_COMMENT, "List of registered IKE Hash Algorithms:");
whack_log(RC_COMMENT, " ");
for (a = ike_alg_base[IKE_ALG_HASH]; a != NULL; a = a->algo_next)
{
whack_log(RC_COMMENT, "#%-5d %s, hashsize: %d"
, a->algo_id
, enum_name(&oakley_hash_names, a->algo_id)
, (int)((struct hash_desc *)a)->hash_digest_size*BITS_PER_BYTE
);
}
whack_log(RC_COMMENT, " ");
whack_log(RC_COMMENT, "List of registered IKE DH Groups:");
whack_log(RC_COMMENT, " ");
for (i = 0; i < elemsof(oakley_group); i++)
{
const struct oakley_group_desc *gdesc=oakley_group + i;
whack_log(RC_COMMENT, "#%-5d %s, groupsize: %d"
, gdesc->group
, enum_name(&oakley_group_names, gdesc->group)
, (int)gdesc->bytes*BITS_PER_BYTE
);
}
}
/* Show IKE algorithms for
* - this connection (result from ike= string)
* - newest SA
*/
void
ike_alg_show_connection(struct connection *c, const char *instance)
{
char buf[256];
struct state *st;
if (c->alg_info_ike)
{
alg_info_snprint(buf, sizeof(buf)-1, (struct alg_info *)c->alg_info_ike);
whack_log(RC_COMMENT
, "\"%s\"%s: IKE algorithms wanted: %s"
, c->name
, instance
, buf
);
alg_info_snprint_ike(buf, sizeof(buf)-1, c->alg_info_ike);
whack_log(RC_COMMENT
, "\"%s\"%s: IKE algorithms found: %s"
, c->name
, instance
, buf
);
}
st = state_with_serialno(c->newest_isakmp_sa);
if (st)
whack_log(RC_COMMENT
, "\"%s\"%s: IKE algorithm newest: %s_%d-%s-%s"
, c->name
, instance
, enum_show(&oakley_enc_names, st->st_oakley.encrypt)
+7 /* strlen("OAKLEY_") */
/* , st->st_oakley.encrypter->keydeflen */
, st->st_oakley.enckeylen
, enum_show(&oakley_hash_names, st->st_oakley.hash)
+7 /* strlen("OAKLEY_") */
, enum_show(&oakley_group_names, st->st_oakley.group->group)
+13 /* strlen("OAKLEY_GROUP_") */
);
}
/*
* ML: make F_STRICT logic consider enc,hash/auth,modp algorithms
*/
bool
ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group
, struct alg_info_ike *alg_info_ike)
{
/*
* simple test to discard low key_len, will accept it only
* if specified in "esp" string
*/
bool ealg_insecure = (key_len < 128);
if (ealg_insecure
|| (alg_info_ike && alg_info_ike->alg_info_flags & ALG_INFO_F_STRICT))
{
int i;
struct ike_info *ike_info;
if (alg_info_ike)
{
ALG_INFO_IKE_FOREACH(alg_info_ike, ike_info, i)
{
if (ike_info->ike_ealg == ealg
&& (ike_info->ike_eklen == 0 || key_len == 0 || ike_info->ike_eklen == key_len)
&& ike_info->ike_halg == aalg
&& ike_info->ike_modp == group)
{
if (ealg_insecure)
loglog(RC_LOG_SERIOUS, "You should NOT use insecure IKE algorithms (%s)!"
, enum_name(&oakley_enc_names, ealg));
return TRUE;
}
}
}
plog("Oakley Transform [%s (%d), %s, %s] refused due to %s"
, enum_name(&oakley_enc_names, ealg), key_len
, enum_name(&oakley_hash_names, aalg)
, enum_name(&oakley_group_names, group)
, ealg_insecure ?
"insecure key_len and enc. alg. not listed in \"ike\" string" : "strict flag"
);
return FALSE;
}
return TRUE;
}
+73
View File
@@ -0,0 +1,73 @@
/* IKE modular algorithm handling interface
* Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
*
* 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: ike_alg.h,v 1.3 2004/09/16 23:22:22 as Exp $
*/
#ifndef _IKE_ALG_H
#define _IKE_ALG_H
#include "connections.h"
struct ike_alg {
u_int16_t algo_type;
u_int16_t algo_id;
struct ike_alg *algo_next;
};
struct encrypt_desc {
u_int16_t algo_type;
u_int16_t algo_id;
struct ike_alg *algo_next;
size_t enc_ctxsize;
size_t enc_blocksize;
u_int keydeflen;
u_int keymaxlen;
u_int keyminlen;
void (*do_crypt)(u_int8_t *dat, size_t datasize, u_int8_t *key, size_t key_size, u_int8_t *iv, bool enc);
};
struct hash_desc {
u_int16_t algo_type;
u_int16_t algo_id;
struct ike_alg *algo_next;
size_t hash_ctx_size;
size_t hash_digest_size;
void (*hash_init)(void *ctx);
void (*hash_update)(void *ctx, const u_int8_t *in, size_t datasize);
void (*hash_final)(u_int8_t *out, void *ctx);
};
#define IKE_ALG_ENCRYPT 0
#define IKE_ALG_HASH 1
#define IKE_ALG_MAX IKE_ALG_HASH
extern int ike_alg_add(struct ike_alg *a);
extern struct hash_desc *ike_alg_get_hasher(u_int alg);
extern struct encrypt_desc *ike_alg_get_encrypter(u_int alg);
extern bool ike_alg_enc_present(u_int ealg);
extern bool ike_alg_hash_present(u_int halg);
extern int ike_alg_register_hash(struct hash_desc *a);
extern int ike_alg_register_enc(struct encrypt_desc *e);
extern const struct oakley_group_desc* ike_alg_pfsgroup(struct connection *c
, lset_t policy);
extern struct db_context * ike_alg_db_new(struct alg_info_ike *ai, lset_t policy);
extern void ike_alg_list(void);
extern void ike_alg_show_connection(struct connection *c, const char *instance);
extern bool ike_alg_ok_final(u_int ealg, u_int key_len, u_int aalg, u_int group
, struct alg_info_ike *alg_info_ike);
extern int ike_alg_init(void);
#endif /* _IKE_ALG_H */
+175
View File
@@ -0,0 +1,175 @@
.TH IPSEC.SECRETS 5 "28 March 1999"
.SH NAME
ipsec.secrets \- secrets for IKE/IPsec authentication
.SH DESCRIPTION
The file \fIipsec.secrets\fP holds a table of secrets.
These secrets are used by \fIipsec_pluto\fP(8), the FreeS/WAN Internet Key
Exchange daemon, to authenticate other hosts.
Currently there are two kinds of secrets: preshared secrets and
.\" the private part of DSS keys.
RSA private keys.
.LP
It is vital that these secrets be protected. The file should be owned
by the super-user,
and its permissions should be set to block all access by others.
.LP
The file is a sequence of entries and include directives.
Here is an example. Each entry or directive must start at the
left margin, but if it continues beyond a single line, each continuation
line must be indented.
.LP
.RS
.nf
# sample /etc/ipsec.secrets file for 10.1.0.1
10.1.0.1 10.2.0.1: PSK "secret shared by two hosts"
# an entry may be split across lines,
# but indentation matters
www.xs4all.nl @www.kremvax.ru
\ \ \ \ 10.6.0.1 10.7.0.1 1.8.0.1: PSK "secret shared by 5"
.\" # Private part of our DSS key, in base 64,
.\" # as generated by BIND 8.2.1's dnskeygen.
.\" # Since this is the default key for this host,
.\" # there is no need to specify indices.
.\" : DSS 0siMs0N/hfRoCBMXA6plPtuv58/+c=
# an RSA private key.
# note that the lines are too wide for a
# man page, so ... has been substituted for
# the truncated part
@my.com: rsa {
\ \ \ \ Modulus:\ 0syXpo/6waam+ZhSs8Lt6jnBzu3C4grtt...
\ \ \ \ PublicExponent:\ 0sAw==
\ \ \ \ PrivateExponent:\ 0shlGbVR1m8Z+7rhzSyenCaBN...
\ \ \ \ Prime1:\ 0s8njV7WTxzVzRz7AP+0OraDxmEAt1BL5l...
\ \ \ \ Prime2:\ 0s1LgR7/oUMo9BvfU8yRFNos1s211KX5K0...
\ \ \ \ Exponent1:\ 0soaXj85ihM5M2inVf/NfHmtLutVz4r...
\ \ \ \ Exponent2:\ 0sjdAL9VFizF+BKU4ohguJFzOd55OG6...
\ \ \ \ Coefficient:\ 0sK1LWwgnNrNFGZsS/2GuMBg9nYVZ...
\ \ \ \ }
include ipsec.*.secrets # get secrets from other files
.fi
.RE
.LP
Each entry in the file is a list of indices, followed by a secret.
The two parts are separated by a colon (\fB:\fP) that is
followed by whitespace or a newline. For compatability
with the previous form of this file, if the key part is just a
double-quoted string the colon may be left out.
.LP
An index is an IP address, or a Fully Qualified Domain Name, user@FQDN,
\fB%any\fP or \fB%any6\fP (other kinds may come). An IP address may be written
in the familiar dotted quad form or as a domain name to be looked up
when the file is loaded
(or in any of the forms supported by the FreeS/WAN \fIipsec_ttoaddr\fP(3)
routine). In many cases it is a bad idea to use domain names because
the name server may not be running or may be insecure. To denote a
Fully Qualified Domain Name (as opposed to an IP address denoted by
its domain name), precede the name with an at sign (\fB@\fP).
.LP
Matching IDs with indices is fairly straightforward: they have to be
equal. In the case of a ``Road Warrior'' connection, if an equal
match is not found for the Peer's ID, and it is in the form of an IP
address, an index of \fB%any\fP will match the peer's IP address if IPV4
and \fB%any6\fP will match a the peer's IP address if IPV6.
Currently, the obsolete notation \fB0.0.0.0\fP may be used in place of
\fB%any\fP.
.LP
An additional complexity
arises in the case of authentication by preshared secret: the
responder will need to look up the secret before the Peer's ID payload has
been decoded, so the ID used will be the IP address.
.LP
To authenticate a connection between two hosts, the entry that most
specifically matches the host and peer IDs is used. An entry with no
index will match any host and peer. More specifically, an entry with one index will
match a host and peer if the index matches the host's ID (the peer isn't
considered). Still more specifically, an entry with multiple indices will match a host and
peer if the host ID and peer ID each match one of the indices. If the key
is for an asymmetric authentication technique (i.e. a public key
system such as RSA), an entry with multiple indices will match a host
and peer even if only the host ID matches an index (it is presumed that the
multiple indices are all identities of the host).
It is acceptable for two entries to be the best match as
long as they agree about the secret or private key.
.LP
Authentication by preshared secret requires that both systems find the
identical secret (the secret is not actually transmitted by the IKE
protocol). If both the host and peer appear in the index list, the
same entry will be suitable for both systems so verbatim copying
between systems can be used. This naturally extends to larger groups
sharing the same secret. Thus multiple-index entries are best for PSK
authentication.
.LP
Authentication by RSA Signatures requires that each host have its own private
key. A host could reasonably use a different private keys
for different interfaces and for different peers. But it would not
be normal to share entries between systems. Thus thus no-index and
one-index forms of entry often make sense for RSA Signature authentication.
.LP
The key part of an entry may start with a token indicating the kind of
key. ``RSA'' signifies RSA private key and ``PSK'' signifies
PreShared Key (case is ignored). For compatability with previous
forms of this file, PSK is the default.
.LP
A preshared secret is most conveniently represented as a sequence of
characters, delimited by the double-quote
character (\fB"\fP). The sequence cannot contain a newline or
double-quote. Strictly speaking, the secret is actually the sequence
of bytes that is used in the file to represent the sequence of
characters (excluding the delimiters).
A preshared secret may also be represented, without quotes, in any form supported by
\fIipsec_ttodata\fP(3).
.LP
An RSA private key is a composite of eight generally large numbers. The notation
used is a brace-enclosed list of field name and value pairs (see the example above).
A suitable key, in a suitable format, may be generated by \fIipsec_rsasigkey\fP(8).
The structure is very similar to that used by BIND 8.2.2 or later, but note that
the numbers must have a ``0s'' prefix if they are in base 64. The order of
the fields is fixed.
.LP
The first token an entry must start in
the first column of its line. Subsequent tokens must be
separated by whitespace,
except for a colon token, which only needs to be followed by whitespace.
A newline is taken as whitespace, but every
line of an entry after the first must be indented.
.LP
Whitespace at the end of a line is ignored (except in the 0t
notation for a key). At the start of line or
after whitespace, \fB#\fP and the following text up to the end of the
line is treated as a comment. Within entries, all lines must be
indented (except for lines with no tokens).
Outside entries, no line may be indented (this is to make sure that
the file layout reflects its structure).
.LP
An include directive causes the contents of the named file to be processed
before continuing with the current file. The filename is subject to
``globbing'' as in \fIsh\fP(1), so every file with a matching name
is processed. Includes may be nested to a modest
depth (10, currently). If the filename doesn't start with a \fB/\fP, the
directory containing the current file is prepended to the name. The
include directive is a line that starts with the word \fBinclude\fP,
followed by whitespace, followed by the filename (which must not contain
whitespace).
.SH FILES
/etc/ipsec.secrets
.SH SEE ALSO
The rest of the FreeS/WAN distribution, in particular
\fIipsec.conf\fP(5),
\fIipsec\fP(8),
\fIipsec_newhostkey\fP(8),
\fIipsec_rsasigkey\fP(8),
\fIipsec_showhostkey\fP(8),
\fIipsec_auto\fP(8) \fB\-\-rereadsecrets\fP,
and \fIipsec_pluto\fP(8) \fB\-\-listen\fP,.
.br
BIND 8.2.2 or later, ftp://ftp.isc.org/isc/bind/src/
.SH HISTORY
Designed for the FreeS/WAN project
<http://www.freeswan.org>
by D. Hugh Redelmeier.
.SH BUGS
If an ID is \fB0.0.0.0\fP, it will match \fB%any\fP;
if it is \fB0::0\fP, it will match \fB%any6\fP.
File diff suppressed because it is too large Load Diff
+104
View File
@@ -0,0 +1,104 @@
/* IPsec DOI and Oakley resolution routines
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
*
* 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.h,v 1.3 2005/01/06 22:10:44 as Exp $
*/
extern void echo_hdr(struct msg_digest *md, bool enc, u_int8_t np);
extern void ipsecdoi_initiate(int whack_sock, struct connection *c
, lset_t policy, unsigned long try, so_serial_t replacing);
extern void ipsecdoi_replace(struct state *st, unsigned long try);
extern void init_phase2_iv(struct state *st, const msgid_t *msgid);
extern stf_status quick_outI1(int whack_sock
, struct state *isakmp_sa
, struct connection *c
, lset_t policy
, unsigned long try
, so_serial_t replacing);
extern state_transition_fn
main_inI1_outR1,
main_inR1_outI2,
main_inI2_outR2,
main_inR2_outI3,
main_inI3_outR3,
main_inR3,
quick_inI1_outR1,
quick_inR1_outI2,
quick_inI2;
extern void send_delete(struct state *st);
extern void accept_delete(struct state *st, struct msg_digest *md
, struct payload_digest *p);
extern void close_message(pb_stream *pbs);
extern bool encrypt_message(pb_stream *pbs, struct state *st);
extern void send_notification_from_state(struct state *st,
enum state_kind state, u_int16_t type);
extern void send_notification_from_md(struct msg_digest *md, u_int16_t type);
extern const char *init_pluto_vendorid(void);
extern void dpd_outI(struct state *st);
extern stf_status dpd_inI_outR(struct state *st
, struct isakmp_notification *const n, pb_stream *n_pbs);
extern stf_status dpd_inR(struct state *st
, struct isakmp_notification *const n, pb_stream *n_pbs);
extern void dpd_timeout(struct state *st);
/* START_HASH_PAYLOAD
*
* Emit a to-be-filled-in hash payload, noting the field start (r_hashval)
* and the start of the part of the message to be hashed (r_hash_start).
* This macro is magic.
* - it can cause the caller to return
* - it references variables local to the caller (r_hashval, r_hash_start, st)
*/
#define START_HASH_PAYLOAD(rbody, np) { \
pb_stream hash_pbs; \
if (!out_generic(np, &isakmp_hash_desc, &(rbody), &hash_pbs)) \
return STF_INTERNAL_ERROR; \
r_hashval = hash_pbs.cur; /* remember where to plant value */ \
if (!out_zero(st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH")) \
return STF_INTERNAL_ERROR; \
close_output_pbs(&hash_pbs); \
r_hash_start = (rbody).cur; /* hash from after HASH payload */ \
}
/* CHECK_QUICK_HASH
*
* This macro is magic -- it cannot be expressed as a function.
* - it causes the caller to return!
* - it declares local variables and expects the "do_hash" argument
* expression to reference them (hash_val, hash_pbs)
*/
#define CHECK_QUICK_HASH(md, do_hash, hash_name, msg_name) { \
pb_stream *const hash_pbs = &md->chain[ISAKMP_NEXT_HASH]->pbs; \
u_char hash_val[MAX_DIGEST_LEN]; \
size_t hash_len = do_hash; \
if (pbs_left(hash_pbs) != hash_len \
|| memcmp(hash_pbs->cur, hash_val, hash_len) != 0) \
{ \
DBG_cond_dump(DBG_CRYPT, "received " hash_name ":", hash_pbs->cur, pbs_left(hash_pbs)); \
loglog(RC_LOG_SERIOUS, "received " hash_name " does not match computed value in " msg_name); \
/* XXX Could send notification back */ \
return STF_FAIL + INVALID_HASH_INFORMATION; \
} \
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef __IPSEC_H
#define __IPSEC_H 1
/* The definitions, required to talk to KAME racoon IKE. */
#define IPSEC_PORT_ANY 0
#define IPSEC_ULPROTO_ANY 255
#define IPSEC_PROTO_ANY 255
enum {
IPSEC_MODE_ANY = 0, /* We do not support this for SA */
IPSEC_MODE_TRANSPORT = 1,
IPSEC_MODE_TUNNEL = 2
};
enum {
IPSEC_DIR_ANY = 0,
IPSEC_DIR_INBOUND = 1,
IPSEC_DIR_OUTBOUND = 2,
IPSEC_DIR_FWD = 3, /* It is our own */
IPSEC_DIR_MAX = 4,
IPSEC_DIR_INVALID = 5
};
enum {
IPSEC_POLICY_DISCARD = 0,
IPSEC_POLICY_NONE = 1,
IPSEC_POLICY_IPSEC = 2,
IPSEC_POLICY_ENTRUST = 3,
IPSEC_POLICY_BYPASS = 4
};
enum {
IPSEC_LEVEL_DEFAULT = 0,
IPSEC_LEVEL_USE = 1,
IPSEC_LEVEL_REQUIRE = 2,
IPSEC_LEVEL_UNIQUE = 3
};
#define IPSEC_MANUAL_REQID_MAX 0x3fff
#define IPSEC_REPLAYWSIZE 32
#define IP_IPSEC_POLICY 16
#define IPV6_IPSEC_POLICY 34
#endif /* __IPSEC_H */
+2997
View File
File diff suppressed because it is too large Load Diff
+200
View File
@@ -0,0 +1,200 @@
/* declarations of routines that interface with the kernel's IPsec mechanism
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: kernel.h,v 1.10 2006/03/08 22:12:37 as Exp $
*/
#include "connections.h"
extern bool no_klips; /* don't actually use KLIPS */
extern bool can_do_IPcomp; /* can system actually perform IPCOMP? */
#ifdef KLIPS
/* Declare eroute things early enough for uses.
*
* Flags are encoded above the low-order byte of verbs.
* "real" eroutes are only outbound. Inbound eroutes don't exist,
* but an addflow with an INBOUND flag allows IPIP tunnels to be
* limited to appropriate source and destination addresses.
*/
#define ERO_MASK 0xFF
#define ERO_FLAG_SHIFT 8
#define ERO_DELETE SADB_X_DELFLOW
#define ERO_ADD SADB_X_ADDFLOW
#define ERO_REPLACE (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT))
#define ERO_ADD_INBOUND (SADB_X_ADDFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
#define ERO_DEL_INBOUND (SADB_X_DELFLOW | (SADB_X_SAFLAGS_INFLOW << ERO_FLAG_SHIFT))
struct pfkey_proto_info {
int proto;
int encapsulation;
unsigned reqid;
};
struct sadb_msg;
struct kernel_sa {
const ip_address *src;
const ip_address *dst;
const ip_subnet *src_client;
const ip_subnet *dst_client;
ipsec_spi_t spi;
unsigned proto;
unsigned satype;
unsigned transport_proto;
unsigned replay_window;
unsigned reqid;
unsigned authalg;
unsigned authkeylen;
char *authkey;
unsigned encalg;
unsigned enckeylen;
char *enckey;
unsigned compalg;
int encapsulation;
#ifdef NAT_TRAVERSAL
u_int16_t natt_sport, natt_dport;
u_int8_t transid, natt_type;
ip_address *natt_oa;
#endif
const char *text_said;
};
struct kernel_ops {
enum {
KERNEL_TYPE_NONE,
KERNEL_TYPE_KLIPS,
KERNEL_TYPE_LINUX,
} type;
bool inbound_eroute;
bool policy_lifetime;
int *async_fdp;
void (*init)(void);
void (*pfkey_register)(void);
void (*pfkey_register_response)(const struct sadb_msg *msg);
void (*process_queue)(void);
void (*process_msg)(void);
bool (*raw_eroute)(const ip_address *this_host,
const ip_subnet *this_client,
const ip_address *that_host,
const ip_subnet *that_client,
ipsec_spi_t spi,
unsigned int satype,
unsigned int transport_proto,
const struct pfkey_proto_info *proto_info,
time_t use_lifetime,
unsigned int op,
const char *text_said);
bool (*get_policy)(const struct kernel_sa *sa, bool inbound,
time_t *use_time);
bool (*add_sa)(const struct kernel_sa *sa, bool replace);
bool (*grp_sa)(const struct kernel_sa *sa_outer,
const struct kernel_sa *sa_inner);
bool (*del_sa)(const struct kernel_sa *sa);
bool (*get_sa)(const struct kernel_sa *sa, u_int *bytes);
ipsec_spi_t (*get_spi)(const ip_address *src,
const ip_address *dst,
int proto,
bool tunnel_mode,
unsigned reqid,
ipsec_spi_t min,
ipsec_spi_t max,
const char *text_said);
};
extern const struct kernel_ops *kernel_ops;
/* information from /proc/net/ipsec_eroute */
struct eroute_info {
unsigned long count;
ip_subnet ours;
ip_subnet his;
ip_address dst;
ip_said said;
int transport_proto;
struct eroute_info *next;
};
extern struct eroute_info *orphaned_holds;
extern void show_shunt_status(void);
#endif
/* A netlink header defines EM_MAXRELSPIS, the max number of SAs in a group.
* Is there a PF_KEY equivalent?
*/
#ifndef EM_MAXRELSPIS
# define EM_MAXRELSPIS 4 /* AH ESP IPCOMP IPIP */
#endif
extern void record_and_initiate_opportunistic(const ip_subnet *
, const ip_subnet *
, int transport_proto
, const char *why);
extern void init_kernel(void);
extern void scan_proc_shunts(void);
extern bool trap_connection(struct connection *c);
extern void unroute_connection(struct connection *c);
extern bool has_bare_hold(const ip_address *src, const ip_address *dst
, int transport_proto);
extern bool replace_bare_shunt(const ip_address *src, const ip_address *dst
, policy_prio_t policy_prio
, ipsec_spi_t shunt_spi /* in host order! */
, bool repl
, unsigned int transport_proto
, const char *why);
extern bool assign_hold(struct connection *c
, struct spd_route *sr
, int transport_proto
, const ip_address *src, const ip_address *dst);
extern ipsec_spi_t shunt_policy_spi(struct connection *c, bool prospective);
struct state; /* forward declaration of tag */
extern ipsec_spi_t get_ipsec_spi(ipsec_spi_t avoid
, int proto
, struct spd_route *sr
, bool tunnel_mode);
extern ipsec_spi_t get_my_cpi(struct spd_route *sr, bool tunnel_mode);
extern bool install_inbound_ipsec_sa(struct state *st);
extern bool install_ipsec_sa(struct state *st, bool inbound_also);
extern void delete_ipsec_sa(struct state *st, bool inbound_only);
extern bool route_and_eroute(struct connection *c
, struct spd_route *sr
, struct state *st);
extern bool was_eroute_idle(struct state *st, time_t idle_max
, time_t *idle_time);
extern bool get_sa_info(struct state *st, bool inbound, u_int *bytes
, time_t *use_time);
#ifdef NAT_TRAVERSAL
extern bool update_ipsec_sa(struct state *st);
#endif
+775
View File
@@ -0,0 +1,775 @@
/* Kernel runtime algorithm handling interface
* Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
*
* 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: kernel_alg.c,v 1.9 2005/08/17 16:31:24 as Exp $
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/queue.h>
#include <pfkeyv2.h>
#include <pfkey.h>
#include <freeswan.h>
#include <freeswan/ipsec_policy.h>
#include "constants.h"
#include "defs.h"
#include "connections.h"
#include "state.h"
#include "packet.h"
#include "spdb.h"
#include "kernel.h"
#include "kernel_alg.h"
#include "alg_info.h"
#ifndef NO_PLUTO
#include "log.h"
#include "whack.h"
#include "db_ops.h"
#else
/*
* macros/functions for compilation without pluto (eg: spi for manual conns)
*/
extern int debug;
#include <assert.h>
#define passert(x) assert(x)
#define DBG(cond, action) { if (debug) { action ; } }
#define DBG_log(x, args...) fprintf(stderr, x "\n" , ##args);
#define plog(x, args...) fprintf(stderr, x "\n" , ##args);
#endif /* NO_PLUTO */
/* ALG storage */
static struct sadb_alg esp_aalg[SADB_AALG_MAX+1];
static struct sadb_alg esp_ealg[SADB_EALG_MAX+1];
static int esp_ealg_num = 0;
static int esp_aalg_num = 0;
#define ESP_EALG_PRESENT(algo) (((algo)<=SADB_EALG_MAX)&&(esp_ealg[(algo)].sadb_alg_id==(algo)))
#define ESP_EALG_FOR_EACH_UPDOWN(algo) \
for (algo=SADB_EALG_MAX; algo >0 ; algo--) \
if (ESP_EALG_PRESENT(algo))
#define ESP_AALG_PRESENT(algo) ((algo<=SADB_AALG_MAX)&&(esp_aalg[(algo)].sadb_alg_id==(algo)))
#define ESP_AALG_FOR_EACH_UPDOWN(algo) \
for (algo=SADB_AALG_MAX; algo >0 ; algo--) \
if (ESP_AALG_PRESENT(algo))
static struct sadb_alg*
sadb_alg_ptr (int satype, int exttype, int alg_id, int rw)
{
struct sadb_alg *alg_p = NULL;
switch (exttype)
{
case SADB_EXT_SUPPORTED_AUTH:
if (alg_id > SADB_AALG_MAX)
return NULL;
break;
case SADB_EXT_SUPPORTED_ENCRYPT:
if (alg_id > SADB_EALG_MAX)
return NULL;
break;
default:
return NULL;
}
switch (satype)
{
case SADB_SATYPE_ESP:
alg_p = (exttype == SADB_EXT_SUPPORTED_ENCRYPT)?
&esp_ealg[alg_id] : &esp_aalg[alg_id];
/* get for write: increment elem count */
if (rw)
{
(exttype == SADB_EXT_SUPPORTED_ENCRYPT)?
esp_ealg_num++ : esp_aalg_num++;
}
break;
case SADB_SATYPE_AH:
default:
return NULL;
}
return alg_p;
}
const struct sadb_alg *
kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id)
{
return sadb_alg_ptr(satype, exttype, alg_id, 0);
}
/*
* Forget previous registration
*/
static void
kernel_alg_init(void)
{
DBG(DBG_KLIPS,
DBG_log("alg_init(): memset(%p, 0, %d) memset(%p, 0, %d)",
&esp_aalg, (int)sizeof (esp_aalg),
&esp_ealg, (int)sizeof (esp_ealg))
)
memset (&esp_aalg, 0, sizeof (esp_aalg));
memset (&esp_ealg, 0, sizeof (esp_ealg));
esp_ealg_num=esp_aalg_num = 0;
}
static int
kernel_alg_add(int satype, int exttype, const struct sadb_alg *sadb_alg)
{
struct sadb_alg *alg_p = NULL;
int alg_id = sadb_alg->sadb_alg_id;
DBG(DBG_KLIPS,
DBG_log("kernel_alg_add(): satype=%d, exttype=%d, alg_id=%d",
satype, exttype, sadb_alg->sadb_alg_id)
)
if (!(alg_p = sadb_alg_ptr(satype, exttype, alg_id, 1)))
return -1;
/* This logic "mimics" KLIPS: first algo implementation will be used */
if (alg_p->sadb_alg_id)
{
DBG(DBG_KLIPS,
DBG_log("kernel_alg_add(): discarding already setup "
"satype=%d, exttype=%d, alg_id=%d",
satype, exttype, sadb_alg->sadb_alg_id)
)
return 0;
}
*alg_p = *sadb_alg;
return 1;
}
bool
kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len,
struct alg_info_esp *alg_info __attribute__((unused)))
{
struct sadb_alg *alg_p = NULL;
/*
* test #1: encrypt algo must be present
*/
int ret = ESP_EALG_PRESENT(alg_id);
if (!ret) goto out;
alg_p = &esp_ealg[alg_id];
/*
* test #2: if key_len specified, it must be in range
*/
if (key_len
&& (key_len < alg_p->sadb_alg_minbits || key_len > alg_p->sadb_alg_maxbits))
{
plog("kernel_alg_db_add() key_len not in range: alg_id=%d, "
"key_len=%d, alg_minbits=%d, alg_maxbits=%d"
, alg_id, key_len
, alg_p->sadb_alg_minbits
, alg_p->sadb_alg_maxbits);
ret = FALSE;
}
out:
if (ret)
{
DBG(DBG_KLIPS,
DBG_log("kernel_alg_esp_enc_ok(%d,%d): "
"alg_id=%d, "
"alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
"res=%d, ret=%d"
, alg_id, key_len
, alg_p->sadb_alg_id
, alg_p->sadb_alg_ivlen
, alg_p->sadb_alg_minbits
, alg_p->sadb_alg_maxbits
, alg_p->sadb_alg_reserved
, ret);
)
}
else
{
DBG(DBG_KLIPS,
DBG_log("kernel_alg_esp_enc_ok(%d,%d): NO", alg_id, key_len);
)
}
return ret;
}
/*
* ML: make F_STRICT logic consider enc,auth algorithms
*/
#ifndef NO_PLUTO
bool
kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info)
{
int ealg_insecure;
/*
* key_len passed comes from esp_attrs read from peer
* For many older algoritms (eg 3DES) this key_len is fixed
* and get passed as 0.
* ... then get default key_len
*/
if (key_len == 0)
key_len = kernel_alg_esp_enc_keylen(ealg) * BITS_PER_BYTE;
/*
* simple test to toss low key_len, will accept it only
* if specified in "esp" string
*/
ealg_insecure = (key_len < 128) ;
if (ealg_insecure
|| (alg_info && alg_info->alg_info_flags & ALG_INFO_F_STRICT))
{
int i;
struct esp_info *esp_info;
if (alg_info)
{
ALG_INFO_ESP_FOREACH(alg_info, esp_info, i)
{
if (esp_info->esp_ealg_id == ealg
&& (esp_info->esp_ealg_keylen == 0 || key_len == 0
|| esp_info->esp_ealg_keylen == key_len)
&& esp_info->esp_aalg_id == aalg)
{
if (ealg_insecure)
{
loglog(RC_LOG_SERIOUS
, "You should NOT use insecure ESP algorithms [%s (%d)]!"
, enum_name(&esp_transformid_names, ealg), key_len);
}
return TRUE;
}
}
}
plog("IPSec Transform [%s (%d), %s] refused due to %s",
enum_name(&esp_transformid_names, ealg), key_len,
enum_name(&auth_alg_names, aalg),
ealg_insecure ? "insecure key_len and enc. alg. not listed in \"esp\" string" : "strict flag");
return FALSE;
}
return TRUE;
}
#endif /* NO_PLUTO */
/*
* Load kernel_alg arrays from /proc
* used in manual mode from klips/utils/spi.c
*/
int
kernel_alg_proc_read(void)
{
int satype;
int supp_exttype;
int alg_id, ivlen, minbits, maxbits;
struct sadb_alg sadb_alg;
int ret;
char buf[128];
FILE *fp=fopen("/proc/net/pf_key_supported", "r");
if (!fp)
return -1;
kernel_alg_init();
while (fgets(buf, sizeof(buf), fp))
{
if (buf[0] != ' ') /* skip titles */
continue;
sscanf(buf, "%d %d %d %d %d %d"
,&satype, &supp_exttype
, &alg_id, &ivlen
, &minbits, &maxbits);
switch (satype)
{
case SADB_SATYPE_ESP:
switch(supp_exttype)
{
case SADB_EXT_SUPPORTED_AUTH:
case SADB_EXT_SUPPORTED_ENCRYPT:
sadb_alg.sadb_alg_id = alg_id;
sadb_alg.sadb_alg_ivlen = ivlen;
sadb_alg.sadb_alg_minbits = minbits;
sadb_alg.sadb_alg_maxbits = maxbits;
ret = kernel_alg_add(satype, supp_exttype, &sadb_alg);
DBG(DBG_CRYPT,
DBG_log("kernel_alg_proc_read() alg_id=%d, "
"alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
"ret=%d"
, sadb_alg.sadb_alg_id
, sadb_alg.sadb_alg_ivlen
, sadb_alg.sadb_alg_minbits
, sadb_alg.sadb_alg_maxbits
, ret)
)
}
default:
continue;
}
}
fclose(fp);
return 0;
}
/*
* Load kernel_alg arrays pluto's SADB_REGISTER
* user by pluto/kernel.c
*/
void
kernel_alg_register_pfkey(const struct sadb_msg *msg_buf, int buflen)
{
/* Trick: one 'type-mangle-able' pointer to ease offset/assign */
union {
const struct sadb_msg *msg;
const struct sadb_supported *supported;
const struct sadb_ext *ext;
const struct sadb_alg *alg;
const char *ch;
} sadb;
int satype;
int msglen;
int i = 0;
/* Initialize alg arrays */
kernel_alg_init();
satype = msg_buf->sadb_msg_satype;
sadb.msg = msg_buf;
msglen = sadb.msg->sadb_msg_len*IPSEC_PFKEYv2_ALIGN;
msglen -= sizeof(struct sadb_msg);
buflen -= sizeof(struct sadb_msg);
passert(buflen > 0);
sadb.msg++;
while(msglen)
{
int supp_exttype = sadb.supported->sadb_supported_exttype;
int supp_len = sadb.supported->sadb_supported_len*IPSEC_PFKEYv2_ALIGN;
DBG(DBG_KLIPS,
DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
"sadb_msg_len=%d sadb_supported_len=%d"
, satype==SADB_SATYPE_ESP? "ESP" : "AH"
, msg_buf->sadb_msg_len, supp_len)
)
sadb.supported++;
msglen -= supp_len;
buflen -= supp_len;
passert(buflen >= 0);
for (supp_len -= sizeof(struct sadb_supported);
supp_len;
supp_len -= sizeof(struct sadb_alg), sadb.alg++,i++)
{
int ret = kernel_alg_add(satype, supp_exttype, sadb.alg);
DBG(DBG_KLIPS,
DBG_log("kernel_alg_register_pfkey(): SADB_SATYPE_%s: "
"alg[%d], exttype=%d, satype=%d, alg_id=%d, "
"alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d, "
"res=%d, ret=%d"
, satype==SADB_SATYPE_ESP? "ESP" : "AH"
, i
, supp_exttype
, satype
, sadb.alg->sadb_alg_id
, sadb.alg->sadb_alg_ivlen
, sadb.alg->sadb_alg_minbits
, sadb.alg->sadb_alg_maxbits
, sadb.alg->sadb_alg_reserved
, ret)
)
}
}
}
u_int
kernel_alg_esp_enc_keylen(u_int alg_id)
{
u_int keylen = 0;
if (!ESP_EALG_PRESENT(alg_id))
goto none;
keylen = esp_ealg[alg_id].sadb_alg_maxbits/BITS_PER_BYTE;
switch (alg_id)
{
/*
* this is veryUgly[TM]
* Peer should have sent KEY_LENGTH attribute for ESP_AES
* but if not do force it to 128 instead of using sadb_alg_maxbits
* from kernel.
*/
case ESP_AES:
keylen = 128/BITS_PER_BYTE;
break;
}
none:
DBG(DBG_KLIPS,
DBG_log("kernel_alg_esp_enc_keylen():"
"alg_id=%d, keylen=%d",
alg_id, keylen)
)
return keylen;
}
struct sadb_alg *
kernel_alg_esp_sadb_alg(u_int alg_id)
{
struct sadb_alg *sadb_alg = (ESP_EALG_PRESENT(alg_id))
? &esp_ealg[alg_id] : NULL;
DBG(DBG_KLIPS,
DBG_log("kernel_alg_esp_sadb_alg(): alg_id=%d, sadb_alg=%p"
, alg_id, sadb_alg)
)
return sadb_alg;
}
#ifndef NO_PLUTO
void kernel_alg_list(void)
{
u_int sadb_id;
whack_log(RC_COMMENT, " ");
whack_log(RC_COMMENT, "List of registered ESP Encryption Algorithms:");
whack_log(RC_COMMENT, " ");
for (sadb_id = 1; sadb_id <= SADB_EALG_MAX; sadb_id++)
{
if (ESP_EALG_PRESENT(sadb_id))
{
struct sadb_alg *alg_p = &esp_ealg[sadb_id];
whack_log(RC_COMMENT, "#%-5d %s, blocksize: %d, keylen: %d-%d"
, sadb_id
, enum_name(&esp_transformid_names, sadb_id)
, alg_p->sadb_alg_ivlen
, alg_p->sadb_alg_minbits
, alg_p->sadb_alg_maxbits
);
}
}
whack_log(RC_COMMENT, " ");
whack_log(RC_COMMENT, "List of registered ESP Authentication Algorithms:");
whack_log(RC_COMMENT, " ");
for (sadb_id = 1; sadb_id <= SADB_AALG_MAX; sadb_id++)
{
if (ESP_AALG_PRESENT(sadb_id))
{
u_int aaid = alg_info_esp_sadb2aa(sadb_id);
struct sadb_alg *alg_p = &esp_aalg[sadb_id];
whack_log(RC_COMMENT, "#%-5d %s, keylen: %d-%d"
, aaid
, enum_name(&auth_alg_names, aaid)
, alg_p->sadb_alg_minbits
, alg_p->sadb_alg_maxbits
);
}
}
}
void
kernel_alg_show_connection(struct connection *c, const char *instance)
{
char buf[256];
struct state *st;
if (c->alg_info_esp)
{
alg_info_snprint(buf, sizeof(buf), (struct alg_info *)c->alg_info_esp);
whack_log(RC_COMMENT
, "\"%s\"%s: ESP algorithms wanted: %s"
, c->name
, instance
, buf);
}
if (c->alg_info_esp)
{
alg_info_snprint_esp(buf, sizeof(buf), c->alg_info_esp);
whack_log(RC_COMMENT
, "\"%s\"%s: ESP algorithms loaded: %s"
, c->name
, instance
, buf);
}
st = state_with_serialno(c->newest_ipsec_sa);
if (st && st->st_esp.present)
whack_log(RC_COMMENT
, "\"%s\"%s: ESP algorithm newest: %s_%d-%s; pfsgroup=%s"
, c->name
, instance
, enum_show(&esp_transformid_names, st->st_esp.attrs.transid)
+4 /* strlen("ESP_") */
, st->st_esp.attrs.key_len
, enum_show(&auth_alg_names, st->st_esp.attrs.auth)+
+15 /* strlen("AUTH_ALGORITHM_") */
, c->policy & POLICY_PFS ?
c->alg_info_esp->esp_pfsgroup ?
enum_show(&oakley_group_names,
c->alg_info_esp->esp_pfsgroup)
+13 /*strlen("OAKLEY_GROUP_")*/
: "<Phase1>"
: "<N/A>"
);
}
#endif /* NO_PLUTO */
bool
kernel_alg_esp_auth_ok(u_int auth,
struct alg_info_esp *alg_info __attribute__((unused)))
{
return ESP_AALG_PRESENT(alg_info_esp_aa2sadb(auth));
}
u_int
kernel_alg_esp_auth_keylen(u_int auth)
{
u_int sadb_aalg = alg_info_esp_aa2sadb(auth);
u_int a_keylen = (sadb_aalg)
? esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE
: 0;
DBG(DBG_CONTROL | DBG_CRYPT | DBG_PARSING,
DBG_log("kernel_alg_esp_auth_keylen(auth=%d, sadb_aalg=%d): "
"a_keylen=%d", auth, sadb_aalg, a_keylen)
)
return a_keylen;
}
struct esp_info *
kernel_alg_esp_info(int transid, int auth)
{
int sadb_aalg, sadb_ealg;
static struct esp_info ei_buf;
sadb_ealg = transid;
sadb_aalg = alg_info_esp_aa2sadb(auth);
if (!ESP_EALG_PRESENT(sadb_ealg))
goto none;
if (!ESP_AALG_PRESENT(sadb_aalg))
goto none;
memset(&ei_buf, 0, sizeof (ei_buf));
ei_buf.transid = transid;
ei_buf.auth = auth;
/* don't return "default" keylen because this value is used from
* setup_half_ipsec_sa() to "validate" keylen
* In effect, enckeylen will be used as "max" value
*/
ei_buf.enckeylen = esp_ealg[sadb_ealg].sadb_alg_maxbits/BITS_PER_BYTE;
ei_buf.authkeylen = esp_aalg[sadb_aalg].sadb_alg_maxbits/BITS_PER_BYTE;
ei_buf.encryptalg = sadb_ealg;
ei_buf.authalg = sadb_aalg;
DBG(DBG_PARSING,
DBG_log("kernel_alg_esp_info():"
"transid=%d, auth=%d, ei=%p, "
"enckeylen=%d, authkeylen=%d, encryptalg=%d, authalg=%d",
transid, auth, &ei_buf,
(int)ei_buf.enckeylen, (int)ei_buf.authkeylen,
ei_buf.encryptalg, ei_buf.authalg)
)
return &ei_buf;
none:
DBG(DBG_PARSING,
DBG_log("kernel_alg_esp_info():"
"transid=%d, auth=%d, ei=NULL",
transid, auth)
)
return NULL;
}
#ifndef NO_PLUTO
static void
kernel_alg_policy_algorithms(struct esp_info *esp_info)
{
u_int ealg_id = esp_info->esp_ealg_id;
switch(ealg_id)
{
case 0:
case ESP_DES:
case ESP_3DES:
case ESP_NULL:
case ESP_CAST:
break;
default:
if (!esp_info->esp_ealg_keylen)
{
/* algos that need KEY_LENGTH
*
* Note: this is a very dirty hack ;-)
* Idea: Add a key_length_needed attribute to
* esp_ealg ??
*/
esp_info->esp_ealg_keylen = esp_ealg[ealg_id].sadb_alg_maxbits;
}
}
}
static bool
kernel_alg_db_add(struct db_context *db_ctx, struct esp_info *esp_info, lset_t policy)
{
u_int ealg_id, aalg_id;
ealg_id = esp_info->esp_ealg_id;
if (!ESP_EALG_PRESENT(ealg_id))
{
DBG_log("kernel_alg_db_add() kernel enc ealg_id=%d not present", ealg_id);
return FALSE;
}
if (!(policy & POLICY_AUTHENTICATE)) /* skip ESP auth attrs for AH */
{
aalg_id = alg_info_esp_aa2sadb(esp_info->esp_aalg_id);
if (!ESP_AALG_PRESENT(aalg_id))
{
DBG_log("kernel_alg_db_add() kernel auth "
"aalg_id=%d not present", aalg_id);
return FALSE;
}
}
/* do algo policy */
kernel_alg_policy_algorithms(esp_info);
/* open new transformation */
db_trans_add(db_ctx, ealg_id);
/* add ESP auth attr */
if (!(policy & POLICY_AUTHENTICATE))
db_attr_add_values(db_ctx, AUTH_ALGORITHM, esp_info->esp_aalg_id);
/* add keylegth if specified in esp= string */
if (esp_info->esp_ealg_keylen)
db_attr_add_values(db_ctx, KEY_LENGTH, esp_info->esp_ealg_keylen);
return TRUE;
}
/*
* Create proposal with runtime kernel algos, merging
* with passed proposal if not NULL
*
* for now this function does free() previous returned
* malloced pointer (this quirk allows easier spdb.c change)
*/
struct db_context *
kernel_alg_db_new(struct alg_info_esp *alg_info, lset_t policy )
{
const struct esp_info *esp_info;
struct esp_info tmp_esp_info;
struct db_context *ctx_new=NULL;
struct db_trans *t;
struct db_prop *prop;
u_int trans_cnt;
int tn = 0;
if (!(policy & POLICY_ENCRYPT)) /* not possible, I think */
return NULL;
trans_cnt = esp_ealg_num * esp_aalg_num;
DBG(DBG_EMITTING,
DBG_log("kernel_alg_db_prop_new() initial trans_cnt=%d"
, trans_cnt)
)
/* pass aprox. number of transforms and attributes */
ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2);
/*
* Loop: for each element (struct esp_info) of alg_info,
* if kernel support is present then build the transform (and attrs)
* if NULL alg_info, propose everything ...
*/
if (alg_info)
{
int i;
ALG_INFO_ESP_FOREACH(alg_info, esp_info, i)
{
tmp_esp_info = *esp_info;
kernel_alg_db_add(ctx_new, &tmp_esp_info, policy);
}
}
else
{
u_int ealg_id;
ESP_EALG_FOR_EACH_UPDOWN(ealg_id)
{
u_int aalg_id;
tmp_esp_info.esp_ealg_id = ealg_id;
tmp_esp_info.esp_ealg_keylen = 0;
for (aalg_id = 1; aalg_id <= SADB_AALG_MAX; aalg_id++)
{
if (ESP_AALG_PRESENT(aalg_id))
{
tmp_esp_info.esp_aalg_id = alg_info_esp_sadb2aa(aalg_id);
tmp_esp_info.esp_aalg_keylen = 0;
kernel_alg_db_add(ctx_new, &tmp_esp_info, policy);
}
}
}
}
prop = db_prop_get(ctx_new);
DBG(DBG_CONTROL|DBG_EMITTING,
DBG_log("kernel_alg_db_prop_new() "
"will return p_new->protoid=%d, p_new->trans_cnt=%d"
, prop->protoid, prop->trans_cnt)
)
for (t = prop->trans, tn = 0; tn < prop->trans_cnt; tn++)
{
DBG(DBG_CONTROL|DBG_EMITTING,
DBG_log("kernel_alg_db_prop_new() "
" trans[%d]: transid=%d, attr_cnt=%d, "
"attrs[0].type=%d, attrs[0].val=%d"
, tn
, t[tn].transid, t[tn].attr_cnt
, t[tn].attrs[0].type, t[tn].attrs[0].val)
)
}
return ctx_new;
}
#endif /* NO_PLUTO */
+46
View File
@@ -0,0 +1,46 @@
/* Kernel runtime algorithm handling interface definitions
* Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
*
* 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: kernel_alg.h,v 1.5 2005/08/17 16:31:24 as Exp $
*/
#ifndef _KERNEL_ALG_H
#define _KERNEL_ALG_H
#include "alg_info.h"
#include "spdb.h"
/* status info */
extern void kernel_alg_show_status(void);
void kernel_alg_show_connection(struct connection *c, const char *instance);
/* Registration messages from pluto */
extern void kernel_alg_register_pfkey(const struct sadb_msg *msg, int buflen);
/* ESP interface */
extern struct sadb_alg *kernel_alg_esp_sadb_alg(u_int alg_id);
extern u_int kernel_alg_esp_ivlen(u_int alg_id);
extern bool kernel_alg_esp_enc_ok(u_int alg_id, u_int key_len, struct alg_info_esp *nfo);
extern bool kernel_alg_esp_ok_final(u_int ealg, u_int key_len, u_int aalg, struct alg_info_esp *alg_info);
extern u_int kernel_alg_esp_enc_keylen(u_int alg_id);
extern bool kernel_alg_esp_auth_ok(u_int auth, struct alg_info_esp *nfo);
extern u_int kernel_alg_esp_auth_keylen(u_int auth);
extern int kernel_alg_proc_read(void);
extern void kernel_alg_list(void);
/* get sadb_alg for passed args */
extern const struct sadb_alg * kernel_alg_sadb_alg_get(int satype, int exttype, int alg_id);
extern struct db_context * kernel_alg_db_new(struct alg_info_esp *ai, lset_t policy);
struct esp_info * kernel_alg_esp_info(int esp_id, int auth_id);
#endif /* _KERNEL_ALG_H */
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
/* declarations of routines that interface with the kernel's pfkey mechanism
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
* Copyright (C) 2003 Herbert Xu
*
* 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: kernel_netlink.h,v 1.1 2004/03/15 20:35:28 as Exp $
*/
#if defined(KLIPS) && defined(linux)
extern const struct kernel_ops linux_kernel_ops;
#endif
+126
View File
@@ -0,0 +1,126 @@
/* interface to fake kernel interface, used for testing pluto in-vitro.
* Copyright (C) 1997 Angelos D. Keromytis.
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
* Copyright (C) 2003 Michael Richardson <mcr@freeswan.org>
* Copyright (C) 2003 Herbert Xu.
*
* 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: kernel_noklips.c,v 1.5 2006/02/04 00:01:22 as Exp $
*/
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <freeswan.h>
#include <pfkeyv2.h>
#include <pfkey.h>
#include "constants.h"
#include "defs.h"
#include "kernel.h"
#include "kernel_noklips.h"
#include "log.h"
#include "whack.h" /* for RC_LOG_SERIOUS */
void
init_noklips(void)
{
return;
}
/* asynchronous messages from our queue */
static void
noklips_dequeue(void)
{
}
/* asynchronous messages directly from PF_KEY socket */
static void
noklips_event(void)
{
}
static void
noklips_register_response(const struct sadb_msg *msg UNUSED)
{
}
static void
noklips_register(void)
{
}
static bool
noklips_raw_eroute(const ip_address *this_host UNUSED
, const ip_subnet *this_client UNUSED
, const ip_address *that_host UNUSED
, const ip_subnet *that_client UNUSED
, ipsec_spi_t spi UNUSED
, unsigned int satype UNUSED
, unsigned int transport_proto UNUSED
, const struct pfkey_proto_info *proto_info UNUSED
, time_t use_lifetime UNUSED
, unsigned int op UNUSED
, const char *text_said UNUSED)
{
return TRUE;
}
static bool
noklips_add_sa(const struct kernel_sa *sa UNUSED
, bool replace UNUSED)
{
return TRUE;
}
static bool
noklips_grp_sa(const struct kernel_sa *sa0 UNUSED
, const struct kernel_sa *sa1 UNUSED)
{
return TRUE;
}
static bool
noklips_del_sa(const struct kernel_sa *sa UNUSED)
{
return TRUE;
}
const struct kernel_ops noklips_kernel_ops = {
type: KERNEL_TYPE_NONE,
async_fdp: NULL,
init: init_noklips,
pfkey_register: noklips_register,
pfkey_register_response: noklips_register_response,
process_queue: noklips_dequeue,
process_msg: noklips_event,
raw_eroute: noklips_raw_eroute,
add_sa: noklips_add_sa,
grp_sa: noklips_grp_sa,
del_sa: noklips_del_sa,
get_sa: NULL,
get_spi: NULL,
inbound_eroute: FALSE,
policy_lifetime: FALSE
};
+19
View File
@@ -0,0 +1,19 @@
/* declarations of routines that interface with the kernel's pfkey mechanism
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
* Copyright (C) 2003 Herbert Xu
*
* 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: kernel_noklips.h,v 1.1 2004/03/15 20:35:28 as Exp $
*/
extern void init_noklips(void);
extern const struct kernel_ops noklips_kernel_ops;
+938
View File
@@ -0,0 +1,938 @@
/* pfkey interface to the kernel's IPsec mechanism
* Copyright (C) 1997 Angelos D. Keromytis.
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
* Copyright (C) 2003 Herbert Xu.
*
* 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: kernel_pfkey.c,v 1.8 2006/02/04 00:01:22 as Exp $
*/
#ifdef KLIPS
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <freeswan.h>
#include <pfkeyv2.h>
#include <pfkey.h>
#include "constants.h"
#include "defs.h"
#include "kernel.h"
#include "kernel_pfkey.h"
#include "log.h"
#include "whack.h" /* for RC_LOG_SERIOUS */
#ifdef NAT_TRAVERSAL
#include "demux.h"
#include "nat_traversal.h"
#endif
#include "alg_info.h"
#include "kernel_alg.h"
static int pfkeyfd = NULL_FD;
typedef u_int32_t pfkey_seq_t;
static pfkey_seq_t pfkey_seq = 0; /* sequence number for our PF_KEY messages */
static pid_t pid;
#define NE(x) { x, #x } /* Name Entry -- shorthand for sparse_names */
static sparse_names pfkey_type_names = {
NE(SADB_RESERVED),
NE(SADB_GETSPI),
NE(SADB_UPDATE),
NE(SADB_ADD),
NE(SADB_DELETE),
NE(SADB_GET),
NE(SADB_ACQUIRE),
NE(SADB_REGISTER),
NE(SADB_EXPIRE),
NE(SADB_FLUSH),
NE(SADB_DUMP),
NE(SADB_X_PROMISC),
NE(SADB_X_PCHANGE),
NE(SADB_X_GRPSA),
NE(SADB_X_ADDFLOW),
NE(SADB_X_DELFLOW),
NE(SADB_X_DEBUG),
#ifdef NAT_TRAVERSAL
NE(SADB_X_NAT_T_NEW_MAPPING),
#endif
NE(SADB_MAX),
{ 0, sparse_end }
};
#ifdef NEVER /* not needed yet */
static sparse_names pfkey_ext_names = {
NE(SADB_EXT_RESERVED),
NE(SADB_EXT_SA),
NE(SADB_EXT_LIFETIME_CURRENT),
NE(SADB_EXT_LIFETIME_HARD),
NE(SADB_EXT_LIFETIME_SOFT),
NE(SADB_EXT_ADDRESS_SRC),
NE(SADB_EXT_ADDRESS_DST),
NE(SADB_EXT_ADDRESS_PROXY),
NE(SADB_EXT_KEY_AUTH),
NE(SADB_EXT_KEY_ENCRYPT),
NE(SADB_EXT_IDENTITY_SRC),
NE(SADB_EXT_IDENTITY_DST),
NE(SADB_EXT_SENSITIVITY),
NE(SADB_EXT_PROPOSAL),
NE(SADB_EXT_SUPPORTED_AUTH),
NE(SADB_EXT_SUPPORTED_ENCRYPT),
NE(SADB_EXT_SPIRANGE),
NE(SADB_X_EXT_KMPRIVATE),
NE(SADB_X_EXT_SATYPE2),
NE(SADB_X_EXT_SA2),
NE(SADB_X_EXT_ADDRESS_DST2),
NE(SADB_X_EXT_ADDRESS_SRC_FLOW),
NE(SADB_X_EXT_ADDRESS_DST_FLOW),
NE(SADB_X_EXT_ADDRESS_SRC_MASK),
NE(SADB_X_EXT_ADDRESS_DST_MASK),
NE(SADB_X_EXT_DEBUG),
{ 0, sparse_end }
};
#endif /* NEVER */
#undef NE
void
init_pfkey(void)
{
pid = getpid();
/* open PF_KEY socket */
pfkeyfd = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
if (pfkeyfd == -1)
exit_log_errno((e, "socket() in init_pfkeyfd()"));
#ifdef NEVER /* apparently unsupported! */
if (fcntl(pfkeyfd, F_SETFL, O_NONBLOCK) != 0)
exit_log_errno((e, "fcntl(O_NONBLOCK) in init_pfkeyfd()"));
#endif
if (fcntl(pfkeyfd, F_SETFD, FD_CLOEXEC) != 0)
exit_log_errno((e, "fcntl(FD_CLOEXEC) in init_pfkeyfd()"));
DBG(DBG_KLIPS,
DBG_log("process %u listening for PF_KEY_V2 on file descriptor %d", (unsigned)pid, pfkeyfd));
}
/* Kinds of PF_KEY message from the kernel:
* - response to a request from us
* + ACK/NAK
* + Register: indicates transforms supported by kernel
* + SPI requested by getspi
* - Acquire, requesting us to deal with trapped clear packet
* - expiration of of one of our SAs
* - messages to other processes
*
* To minimize the effect on the event-driven structure of Pluto,
* responses are dealt with synchronously. We hope that the Kernel
* produces them synchronously. We must "read ahead" in the PF_KEY
* stream, saving Acquire and Expiry messages that are encountered.
* We ignore messages to other processes.
*/
typedef union {
unsigned char bytes[PFKEYv2_MAX_MSGSIZE];
struct sadb_msg msg;
} pfkey_buf;
/* queue of unprocessed PF_KEY messages input from kernel
* Note that the pfkey_buf may be partly allocated, reflecting
* the variable length nature of the messages. So the link field
* must come first.
*/
typedef struct pfkey_item {
struct pfkey_item *next;
pfkey_buf buf;
} pfkey_item;
static pfkey_item *pfkey_iq_head = NULL; /* oldest */
static pfkey_item *pfkey_iq_tail; /* youngest */
static bool
pfkey_input_ready(void)
{
fd_set readfds;
int ndes;
struct timeval tm;
tm.tv_sec = 0; /* don't wait at all */
tm.tv_usec = 0;
FD_ZERO(&readfds); /* we only care about pfkeyfd */
FD_SET(pfkeyfd, &readfds);
do {
ndes = select(pfkeyfd + 1, &readfds, NULL, NULL, &tm);
} while (ndes == -1 && errno == EINTR);
if (ndes < 0)
{
log_errno((e, "select() failed in pfkey_get()"));
return FALSE;
}
if (ndes == 0)
return FALSE; /* nothing to read */
passert(ndes == 1 && FD_ISSET(pfkeyfd, &readfds));
return TRUE;
}
/* get a PF_KEY message from kernel.
* Returns TRUE is message found, FALSE if no message pending,
* and aborts or keeps trying when an error is encountered.
* The only validation of the message is that the message length
* received matches that in the message header, and that the message
* is for this process.
*/
static bool
pfkey_get(pfkey_buf *buf)
{
for (;;)
{
/* len must be less than PFKEYv2_MAX_MSGSIZE,
* so it should fit in an int. We use this fact when printing it.
*/
ssize_t len;
if (!pfkey_input_ready())
return FALSE;
len = read(pfkeyfd, buf->bytes, sizeof(buf->bytes));
if (len < 0)
{
if (errno == EAGAIN)
return FALSE;
log_errno((e, "read() failed in pfkey_get()"));
return FALSE;
}
else if ((size_t) len < sizeof(buf->msg))
{
plog("pfkey_get read truncated PF_KEY message: %d bytes; ignoring message"
, (int) len);
}
else if ((size_t) len != buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN)
{
plog("pfkey_get read PF_KEY message with length %d that doesn't equal sadb_msg_len %u * %u; ignoring message"
, (int) len
, (unsigned) buf->msg.sadb_msg_len
, (unsigned) IPSEC_PFKEYv2_ALIGN);
}
else if (!(buf->msg.sadb_msg_pid == (unsigned)pid
|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_ACQUIRE)
|| (buf->msg.sadb_msg_type == SADB_REGISTER)
#ifdef NAT_TRAVERSAL
|| (buf->msg.sadb_msg_pid == 0 && buf->msg.sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING)
#endif
))
{
/* not for us: ignore */
DBG(DBG_KLIPS,
DBG_log("pfkey_get: ignoring PF_KEY %s message %u for process %u"
, sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
, buf->msg.sadb_msg_seq
, buf->msg.sadb_msg_pid));
}
else
{
DBG(DBG_KLIPS,
DBG_log("pfkey_get: %s message %u"
, sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
, buf->msg.sadb_msg_seq));
return TRUE;
}
}
}
/* get a response to a specific message */
static bool
pfkey_get_response(pfkey_buf *buf, pfkey_seq_t seq)
{
while (pfkey_get(buf))
{
if (buf->msg.sadb_msg_pid == (unsigned)pid
&& buf->msg.sadb_msg_seq == seq)
{
return TRUE;
}
else
{
/* Not for us: queue it. */
size_t bl = buf->msg.sadb_msg_len * IPSEC_PFKEYv2_ALIGN;
pfkey_item *it = alloc_bytes(offsetof(pfkey_item, buf) + bl, "pfkey_item");
memcpy(&it->buf, buf, bl);
it->next = NULL;
if (pfkey_iq_head == NULL)
{
pfkey_iq_head = it;
}
else
{
pfkey_iq_tail->next = it;
}
pfkey_iq_tail = it;
}
}
return FALSE;
}
/* Process a SADB_REGISTER message from the kernel.
* This will be a response to one of ours, but it may be asynchronous
* (if kernel modules are loaded and unloaded).
* Some sanity checking has already been performed.
*/
static void
klips_pfkey_register_response(const struct sadb_msg *msg)
{
/* Find out what the kernel can support.
* In fact, the only question at the moment
* is whether it can support IPcomp.
* So we ignore the rest.
* ??? we really should pay attention to what transforms are supported.
*/
switch (msg->sadb_msg_satype)
{
case SADB_SATYPE_AH:
break;
case SADB_SATYPE_ESP:
#ifndef NO_KERNEL_ALG
kernel_alg_register_pfkey(msg, sizeof (pfkey_buf));
#endif
break;
case SADB_X_SATYPE_COMP:
/* ??? There ought to be an extension to list the
* supported algorithms, but RFC 2367 doesn't
* list one for IPcomp. KLIPS uses SADB_X_CALG_DEFLATE.
* Since we only implement deflate, we'll assume this.
*/
can_do_IPcomp = TRUE;
break;
case SADB_X_SATYPE_IPIP:
break;
default:
break;
}
}
/* Processs a SADB_ACQUIRE message from KLIPS.
* Try to build an opportunistic connection!
* See RFC 2367 "PF_KEY Key Management API, Version 2" 3.1.6
* <base, address(SD), (address(P)), (identity(SD),) (sensitivity,) proposal>
* - extensions for source and data IP addresses
* - optional extensions for identity [not useful for us?]
* - optional extension for sensitivity [not useful for us?]
* - expension for proposal [not useful for us?]
*
* ??? We must use the sequence number in creating an SA.
* We actually need to create up to 4 SAs each way. Which one?
* I guess it depends on the protocol present in the sadb_msg_satype.
* For now, we'll ignore this requirement.
*
* ??? We need some mechanism to make sure that multiple ACQUIRE messages
* don't cause a whole bunch of redundant negotiations.
*/
static void
process_pfkey_acquire(pfkey_buf *buf, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC];
struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST];
int src_proto = srcx->sadb_address_proto;
int dst_proto = dstx->sadb_address_proto;
ip_address *src = (ip_address*)&srcx[1];
ip_address *dst = (ip_address*)&dstx[1];
ip_subnet ours, his;
err_t ugh = NULL;
/* assumption: we're only catching our own outgoing packets
* so source is our end and destination is the other end.
* Verifying this is not actually convenient.
*
* This stylized control structure yields a complaint or
* desired results. For compactness, a pointer value is
* treated as a boolean. Logically, the structure is:
* keep going as long as things are OK.
*/
if (buf->msg.sadb_msg_pid == 0 /* we only wish to hear from kernel */
&& !(ugh = src_proto == dst_proto? NULL : "src and dst protocols differ")
&& !(ugh = addrtypeof(src) == addrtypeof(dst)? NULL : "conflicting address types")
&& !(ugh = addrtosubnet(src, &ours))
&& !(ugh = addrtosubnet(dst, &his)))
record_and_initiate_opportunistic(&ours, &his, src_proto, "%acquire");
if (ugh != NULL)
plog("SADB_ACQUIRE message from KLIPS malformed: %s", ugh);
}
/* Handle PF_KEY messages from the kernel that are not dealt with
* synchronously. In other words, all but responses to PF_KEY messages
* that we sent.
*/
static void
pfkey_async(pfkey_buf *buf)
{
struct sadb_ext *extensions[SADB_EXT_MAX + 1];
if (pfkey_msg_parse(&buf->msg, NULL, extensions, EXT_BITS_OUT))
{
plog("pfkey_async:"
" unparseable PF_KEY message:"
" %s len=%d, errno=%d, seq=%d, pid=%d; message ignored"
, sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
, buf->msg.sadb_msg_len
, buf->msg.sadb_msg_errno
, buf->msg.sadb_msg_seq
, buf->msg.sadb_msg_pid);
}
else
{
DBG(DBG_CONTROL | DBG_KLIPS, DBG_log("pfkey_async:"
" %s len=%u, errno=%u, satype=%u, seq=%u, pid=%u"
, sparse_val_show(pfkey_type_names, buf->msg.sadb_msg_type)
, buf->msg.sadb_msg_len
, buf->msg.sadb_msg_errno
, buf->msg.sadb_msg_satype
, buf->msg.sadb_msg_seq
, buf->msg.sadb_msg_pid));
switch (buf->msg.sadb_msg_type)
{
case SADB_REGISTER:
kernel_ops->pfkey_register_response(&buf->msg);
break;
case SADB_ACQUIRE:
/* to simulate loss of ACQUIRE, delete this call */
process_pfkey_acquire(buf, extensions);
break;
#ifdef NAT_TRAVERSAL
case SADB_X_NAT_T_NEW_MAPPING:
process_pfkey_nat_t_new_mapping(&(buf->msg), extensions);
break;
#endif
default:
/* ignored */
break;
}
}
}
/* asynchronous messages from our queue */
static void
pfkey_dequeue(void)
{
while (pfkey_iq_head != NULL)
{
pfkey_item *it = pfkey_iq_head;
pfkey_async(&it->buf);
pfkey_iq_head = it->next;
pfree(it);
}
/* Handle any orphaned holds, but only if no pfkey input is pending.
* For each, we initiate Opportunistic.
* note: we don't need to advance the pointer because
* record_and_initiate_opportunistic will remove the current
* record each time we call it.
*/
while (orphaned_holds != NULL && !pfkey_input_ready())
record_and_initiate_opportunistic(&orphaned_holds->ours
, &orphaned_holds->his
, orphaned_holds->transport_proto
, "%hold found-pfkey");
}
/* asynchronous messages directly from PF_KEY socket */
static void
pfkey_event(void)
{
pfkey_buf buf;
if (pfkey_get(&buf))
pfkey_async(&buf);
}
static bool
pfkey_build(int error
, const char *description
, const char *text_said
, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
if (error == 0)
{
return TRUE;
}
else
{
loglog(RC_LOG_SERIOUS, "building of %s %s failed, code %d"
, description, text_said, error);
pfkey_extensions_free(extensions);
return FALSE;
}
}
/* pfkey_extensions_init + pfkey_build + pfkey_msg_hdr_build */
static bool
pfkey_msg_start(u_int8_t msg_type
, u_int8_t satype
, const char *description
, const char *text_said
, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
pfkey_extensions_init(extensions);
return pfkey_build(pfkey_msg_hdr_build(&extensions[0], msg_type
, satype, 0, ++pfkey_seq, pid)
, description, text_said, extensions);
}
/* pfkey_build + pfkey_address_build */
static bool
pfkeyext_address(u_int16_t exttype
, const ip_address *address
, const char *description
, const char *text_said
, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
/* the following variable is only needed to silence
* a warning caused by the fact that the argument
* to sockaddrof is NOT pointer to const!
*/
ip_address t = *address;
return pfkey_build(pfkey_address_build(extensions + exttype
, exttype, 0, 0, sockaddrof(&t))
, description, text_said, extensions);
}
/* pfkey_build + pfkey_x_protocol_build */
static bool
pfkeyext_protocol(int transport_proto
, const char *description
, const char *text_said
, struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
return (transport_proto == 0)? TRUE
: pfkey_build(
pfkey_x_protocol_build(extensions + SADB_X_EXT_PROTOCOL, transport_proto)
, description, text_said, extensions);
}
/* Finish (building, sending, accepting response for) PF_KEY message.
* If response isn't NULL, the response from the kernel will be
* placed there (and its errno field will not be examined).
* Returns TRUE iff all appears well.
*/
static bool
finish_pfkey_msg(struct sadb_ext *extensions[SADB_EXT_MAX + 1]
, const char *description
, const char *text_said
, pfkey_buf *response)
{
struct sadb_msg *pfkey_msg;
bool success = TRUE;
int error;
error = pfkey_msg_build(&pfkey_msg, extensions, EXT_BITS_IN);
if (error != 0)
{
loglog(RC_LOG_SERIOUS, "pfkey_msg_build of %s %s failed, code %d"
, description, text_said, error);
success = FALSE;
}
else
{
size_t len = pfkey_msg->sadb_msg_len * IPSEC_PFKEYv2_ALIGN;
DBG(DBG_KLIPS,
DBG_log("finish_pfkey_msg: %s message %u for %s %s"
, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
, pfkey_msg->sadb_msg_seq
, description, text_said);
DBG_dump(NULL, (void *) pfkey_msg, len));
if (!no_klips)
{
ssize_t r = write(pfkeyfd, pfkey_msg, len);
if (r != (ssize_t)len)
{
if (r < 0)
{
log_errno((e
, "pfkey write() of %s message %u"
" for %s %s failed"
, sparse_val_show(pfkey_type_names
, pfkey_msg->sadb_msg_type)
, pfkey_msg->sadb_msg_seq
, description, text_said));
}
else
{
loglog(RC_LOG_SERIOUS
, "ERROR: pfkey write() of %s message %u"
" for %s %s truncated: %ld instead of %ld"
, sparse_val_show(pfkey_type_names
, pfkey_msg->sadb_msg_type)
, pfkey_msg->sadb_msg_seq
, description, text_said
, (long)r, (long)len);
}
success = FALSE;
/* if we were compiled with debugging, but we haven't already
* dumped the KLIPS command, do so.
*/
#ifdef DEBUG
if ((cur_debugging & DBG_KLIPS) == 0)
DBG_dump(NULL, (void *) pfkey_msg, len);
#endif
}
else
{
/* Check response from KLIPS.
* It ought to be an echo, perhaps with additional info.
* If the caller wants it, response will point to space.
*/
pfkey_buf b;
pfkey_buf *bp = response != NULL? response : &b;
if (!pfkey_get_response(bp, ((struct sadb_msg *) extensions[0])->sadb_msg_seq))
{
loglog(RC_LOG_SERIOUS
, "ERROR: no response to our PF_KEY %s message for %s %s"
, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
, description, text_said);
success = FALSE;
}
else if (pfkey_msg->sadb_msg_type != bp->msg.sadb_msg_type)
{
loglog(RC_LOG_SERIOUS
, "FreeS/WAN ERROR: response to our PF_KEY %s message for %s %s was of wrong type (%s)"
, sparse_name(pfkey_type_names, pfkey_msg->sadb_msg_type)
, description, text_said
, sparse_val_show(pfkey_type_names, bp->msg.sadb_msg_type));
success = FALSE;
}
else if (response == NULL && bp->msg.sadb_msg_errno != 0)
{
/* KLIPS is signalling a problem */
loglog(RC_LOG_SERIOUS
, "ERROR: PF_KEY %s response for %s %s included errno %u: %s"
, sparse_val_show(pfkey_type_names, pfkey_msg->sadb_msg_type)
, description, text_said
, (unsigned) bp->msg.sadb_msg_errno
, strerror(bp->msg.sadb_msg_errno));
success = FALSE;
}
}
}
}
/* all paths must exit this way to free resources */
pfkey_extensions_free(extensions);
pfkey_msg_free(&pfkey_msg);
return success;
}
/* register SA types that can be negotiated */
void
pfkey_register_proto(unsigned satype, const char *satypename)
{
struct sadb_ext *extensions[SADB_EXT_MAX + 1];
pfkey_buf pfb;
if (!(pfkey_msg_start(SADB_REGISTER
, satype
, satypename, NULL, extensions)
&& finish_pfkey_msg(extensions, satypename, "", &pfb)))
{
/* ??? should this be loglog */
plog("no KLIPS support for %s", satypename);
}
else
{
kernel_ops->pfkey_register_response(&pfb.msg);
DBG(DBG_KLIPS,
DBG_log("%s registered with kernel.", satypename));
}
}
static void
klips_pfkey_register(void)
{
pfkey_register_proto(SADB_SATYPE_AH, "AH");
pfkey_register_proto(SADB_SATYPE_ESP, "ESP");
can_do_IPcomp = FALSE; /* until we get a response from KLIPS */
pfkey_register_proto(SADB_X_SATYPE_COMP, "IPCOMP");
pfkey_register_proto(SADB_X_SATYPE_IPIP, "IPIP");
}
static bool
pfkey_raw_eroute(const ip_address *this_host
, const ip_subnet *this_client
, const ip_address *that_host
, const ip_subnet *that_client
, ipsec_spi_t spi
, unsigned int satype
, unsigned int transport_proto
, const struct pfkey_proto_info *proto_info UNUSED
, time_t use_lifetime UNUSED
, unsigned int op
, const char *text_said)
{
struct sadb_ext *extensions[SADB_EXT_MAX + 1];
ip_address
sflow_ska,
dflow_ska,
smask_ska,
dmask_ska;
int sport = ntohs(portof(&this_client->addr));
int dport = ntohs(portof(&that_client->addr));
networkof(this_client, &sflow_ska);
maskof(this_client, &smask_ska);
setportof(sport ? ~0:0, &smask_ska);
networkof(that_client, &dflow_ska);
maskof(that_client, &dmask_ska);
setportof(dport ? ~0:0, &dmask_ska);
if (!pfkey_msg_start(op & ERO_MASK, satype
, "pfkey_msg_hdr flow", text_said, extensions))
{
return FALSE;
}
if (op != ERO_DELETE)
{
if (!(pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
, SADB_EXT_SA
, spi /* in network order */
, 0, 0, 0, 0, op >> ERO_FLAG_SHIFT)
, "pfkey_sa add flow", text_said, extensions)
&& pfkeyext_address(SADB_EXT_ADDRESS_SRC, this_host
, "pfkey_addr_s add flow", text_said, extensions)
&& pfkeyext_address(SADB_EXT_ADDRESS_DST, that_host
, "pfkey_addr_d add flow", text_said
, extensions)))
{
return FALSE;
}
}
if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_FLOW, &sflow_ska
, "pfkey_addr_sflow", text_said, extensions))
{
return FALSE;
}
if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_FLOW, &dflow_ska
, "pfkey_addr_dflow", text_said, extensions))
{
return FALSE;
}
if (!pfkeyext_address(SADB_X_EXT_ADDRESS_SRC_MASK, &smask_ska
, "pfkey_addr_smask", text_said, extensions))
{
return FALSE;
}
if (!pfkeyext_address(SADB_X_EXT_ADDRESS_DST_MASK, &dmask_ska
, "pfkey_addr_dmask", text_said, extensions))
{
return FALSE;
}
if (!pfkeyext_protocol(transport_proto
, "pfkey_x_protocol", text_said, extensions))
{
return FALSE;
}
return finish_pfkey_msg(extensions, "flow", text_said, NULL);
}
static bool
pfkey_add_sa(const struct kernel_sa *sa, bool replace)
{
struct sadb_ext *extensions[SADB_EXT_MAX + 1];
return pfkey_msg_start(replace ? SADB_UPDATE : SADB_ADD, sa->satype
, "pfkey_msg_hdr Add SA", sa->text_said, extensions)
&& pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
, SADB_EXT_SA
, sa->spi /* in network order */
, sa->replay_window, SADB_SASTATE_MATURE
, sa->authalg, sa->encalg ? sa->encalg: sa->compalg, 0)
, "pfkey_sa Add SA", sa->text_said, extensions)
&& pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src
, "pfkey_addr_s Add SA", sa->text_said, extensions)
&& pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst
, "pfkey_addr_d Add SA", sa->text_said, extensions)
&& (sa->authkeylen == 0
|| pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_AUTH]
, SADB_EXT_KEY_AUTH, sa->authkeylen * BITS_PER_BYTE
, sa->authkey)
, "pfkey_key_a Add SA", sa->text_said, extensions))
&& (sa->enckeylen == 0
|| pfkey_build(pfkey_key_build(&extensions[SADB_EXT_KEY_ENCRYPT]
, SADB_EXT_KEY_ENCRYPT, sa->enckeylen * BITS_PER_BYTE
, sa->enckey)
, "pfkey_key_e Add SA", sa->text_said, extensions))
#ifdef NAT_TRAVERSAL
&& (sa->natt_type == 0
|| pfkey_build(pfkey_x_nat_t_type_build(
&extensions[SADB_X_EXT_NAT_T_TYPE], sa->natt_type),
"pfkey_nat_t_type Add ESP SA", sa->text_said, extensions))
&& (sa->natt_sport == 0
|| pfkey_build(pfkey_x_nat_t_port_build(
&extensions[SADB_X_EXT_NAT_T_SPORT], SADB_X_EXT_NAT_T_SPORT,
sa->natt_sport), "pfkey_nat_t_sport Add ESP SA", sa->text_said,
extensions))
&& (sa->natt_dport == 0
|| pfkey_build(pfkey_x_nat_t_port_build(
&extensions[SADB_X_EXT_NAT_T_DPORT], SADB_X_EXT_NAT_T_DPORT,
sa->natt_dport), "pfkey_nat_t_dport Add ESP SA", sa->text_said,
extensions))
&& (sa->natt_type == 0 || isanyaddr(sa->natt_oa)
|| pfkeyext_address(SADB_X_EXT_NAT_T_OA, sa->natt_oa
, "pfkey_nat_t_oa Add ESP SA", sa->text_said, extensions))
#endif
&& finish_pfkey_msg(extensions, "Add SA", sa->text_said, NULL);
}
static bool
pfkey_grp_sa(const struct kernel_sa *sa0, const struct kernel_sa *sa1)
{
struct sadb_ext *extensions[SADB_EXT_MAX + 1];
return pfkey_msg_start(SADB_X_GRPSA, sa1->satype
, "pfkey_msg_hdr group", sa1->text_said, extensions)
&& pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
, SADB_EXT_SA
, sa1->spi /* in network order */
, 0, 0, 0, 0, 0)
, "pfkey_sa group", sa1->text_said, extensions)
&& pfkeyext_address(SADB_EXT_ADDRESS_DST, sa1->dst
, "pfkey_addr_d group", sa1->text_said, extensions)
&& pfkey_build(pfkey_x_satype_build(&extensions[SADB_X_EXT_SATYPE2]
, sa0->satype)
, "pfkey_satype group", sa0->text_said, extensions)
&& pfkey_build(pfkey_sa_build(&extensions[SADB_X_EXT_SA2]
, SADB_X_EXT_SA2
, sa0->spi /* in network order */
, 0, 0, 0, 0, 0)
, "pfkey_sa2 group", sa0->text_said, extensions)
&& pfkeyext_address(SADB_X_EXT_ADDRESS_DST2, sa0->dst
, "pfkey_addr_d2 group", sa0->text_said, extensions)
&& finish_pfkey_msg(extensions, "group", sa1->text_said, NULL);
}
static bool
pfkey_del_sa(const struct kernel_sa *sa)
{
struct sadb_ext *extensions[SADB_EXT_MAX + 1];
return pfkey_msg_start(SADB_DELETE, proto2satype(sa->proto)
, "pfkey_msg_hdr delete SA", sa->text_said, extensions)
&& pfkey_build(pfkey_sa_build(&extensions[SADB_EXT_SA]
, SADB_EXT_SA
, sa->spi /* in host order */
, 0, SADB_SASTATE_MATURE, 0, 0, 0)
, "pfkey_sa delete SA", sa->text_said, extensions)
&& pfkeyext_address(SADB_EXT_ADDRESS_SRC, sa->src
, "pfkey_addr_s delete SA", sa->text_said, extensions)
&& pfkeyext_address(SADB_EXT_ADDRESS_DST, sa->dst
, "pfkey_addr_d delete SA", sa->text_said, extensions)
&& finish_pfkey_msg(extensions, "Delete SA", sa->text_said, NULL);
}
void
pfkey_close(void)
{
while (pfkey_iq_head != NULL)
{
pfkey_item *it = pfkey_iq_head;
pfkey_iq_head = it->next;
pfree(it);
}
close(pfkeyfd);
pfkeyfd = NULL_FD;
}
const struct kernel_ops klips_kernel_ops = {
type: KERNEL_TYPE_KLIPS,
async_fdp: &pfkeyfd,
pfkey_register: klips_pfkey_register,
pfkey_register_response: klips_pfkey_register_response,
process_queue: pfkey_dequeue,
process_msg: pfkey_event,
raw_eroute: pfkey_raw_eroute,
add_sa: pfkey_add_sa,
grp_sa: pfkey_grp_sa,
del_sa: pfkey_del_sa,
get_sa: NULL,
get_spi: NULL,
inbound_eroute: FALSE,
policy_lifetime: FALSE,
init: NULL
};
#endif /* KLIPS */
+23
View File
@@ -0,0 +1,23 @@
/* declarations of routines that interface with the kernel's pfkey mechanism
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
* Copyright (C) 2003 Herbert Xu
*
* 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: kernel_pfkey.h,v 1.1 2004/03/15 20:35:28 as Exp $
*/
#ifdef KLIPS
extern void init_pfkey(void);
extern void pfkey_register_proto(unsigned satype, const char *satypename);
extern void pfkey_close(void);
extern const struct kernel_ops klips_kernel_ops;
#endif
+1404
View File
File diff suppressed because it is too large Load Diff
+110
View File
@@ -0,0 +1,110 @@
/* mechanisms for preshared keys (public, private, and preshared secrets)
* Copyright (C) 1998-2002 D. Hugh Redelmeier.
*
* 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: keys.h,v 1.7 2006/01/26 20:10:34 as Exp $
*/
#ifndef _KEYS_H
#define _KEYS_H
#include <gmp.h> /* GNU Multi-Precision library */
#include "pkcs1.h"
#include "certs.h"
#ifndef SHARED_SECRETS_FILE
# define SHARED_SECRETS_FILE "/etc/ipsec.secrets"
#endif
const char *shared_secrets_file;
extern void load_preshared_secrets(int whackfd);
extern void free_preshared_secrets(void);
struct state; /* forward declaration */
enum PrivateKeyKind {
PPK_PSK,
/* PPK_DSS, */ /* not implemented */
PPK_RSA,
PPK_PIN
};
extern const chunk_t *get_preshared_secret(const struct connection *c);
extern err_t unpack_RSA_public_key(RSA_public_key_t *rsa, const chunk_t *pubkey);
extern const RSA_private_key_t *get_RSA_private_key(const struct connection *c);
extern const RSA_private_key_t *get_x509_private_key(const x509cert_t *cert);
/* public key machinery */
typedef struct pubkey pubkey_t;
struct pubkey {
struct id id;
unsigned refcnt; /* reference counted! */
enum dns_auth_level dns_auth_level;
char *dns_sig;
time_t installed_time
, last_tried_time
, last_worked_time
, until_time;
chunk_t issuer;
chunk_t serial;
enum pubkey_alg alg;
union {
RSA_public_key_t rsa;
} u;
};
typedef struct pubkey_list pubkey_list_t;
struct pubkey_list {
pubkey_t *key;
pubkey_list_t *next;
};
extern pubkey_list_t *pubkeys; /* keys from ipsec.conf or from certs */
extern pubkey_t *public_key_from_rsa(const RSA_public_key_t *k);
extern pubkey_list_t *free_public_keyentry(pubkey_list_t *p);
extern void free_public_keys(pubkey_list_t **keys);
extern void free_remembered_public_keys(void);
extern void delete_public_keys(const struct id *id, enum pubkey_alg alg
, chunk_t issuer, chunk_t serial);
extern pubkey_t *reference_key(pubkey_t *pk);
extern void unreference_key(pubkey_t **pkp);
extern err_t add_public_key(const struct id *id
, enum dns_auth_level dns_auth_level
, enum pubkey_alg alg
, const chunk_t *key
, pubkey_list_t **head);
extern bool has_private_key(cert_t cert);
extern void add_x509_public_key(x509cert_t *cert, time_t until
, enum dns_auth_level dns_auth_level);
extern void add_pgp_public_key(pgpcert_t *cert, time_t until
, enum dns_auth_level dns_auth_level);
extern void remove_x509_public_key(const x509cert_t *cert);
extern void list_public_keys(bool utc);
struct gw_info; /* forward declaration of tag (defined in dnskey.h) */
extern void transfer_to_public_keys(struct gw_info *gateways_from_dns
#ifdef USE_KEYRR
, pubkey_list_t **keys
#endif /* USE_KEYRR */
);
#endif /* _KEYS_H */
+213
View File
@@ -0,0 +1,213 @@
/* lexer (lexical analyzer) for control files
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: lex.c,v 1.1 2004/03/15 20:35:28 as Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "whack.h" /* for RC_LOG_SERIOUS */
#include "lex.h"
struct file_lex_position *flp = NULL;
/* Open a file for lexical processing.
* new_flp and name must point into storage with will live
* at least until the file is closed.
*/
bool
lexopen(struct file_lex_position *new_flp, const char *name, bool optional)
{
FILE *f = fopen(name, "r");
if (f == NULL)
{
if (!optional || errno != ENOENT)
log_errno((e, "could not open \"%s\"", name));
return FALSE;
}
else
{
new_flp->previous = flp;
flp = new_flp;
flp->filename = name;
flp->fp = f;
flp->lino = 0;
flp->bdry = B_none;
flp->cur = flp->buffer; /* nothing loaded yet */
flp->under = *flp->cur = '\0';
(void) shift(); /* prime tok */
return TRUE;
}
}
void
lexclose(void)
{
fclose(flp->fp);
flp = flp->previous;
}
/* Token decoding: shift() loads the next token into tok.
* Iff a token starts at the left margin, it is considered
* to be the first in a record. We create a special condition,
* Record Boundary (analogous to EOF), just before such a token.
* We are unwilling to shift through a record boundary:
* it must be overridden first.
* Returns FALSE iff Record Boundary or EOF (i.e. no token);
* tok will then be NULL.
*/
char *tok;
#define tokeq(s) (streq(tok, (s)))
#define tokeqword(s) (strcasecmp(tok, (s)) == 0)
bool
shift(void)
{
char *p = flp->cur;
char *sor = NULL; /* start of record for any new lines */
passert(flp->bdry == B_none);
*p = flp->under;
flp->under = '\0';
for (;;)
{
switch (*p)
{
case '\0': /* end of line */
case '#': /* comment to end of line: treat as end of line */
/* get the next line */
if (fgets(flp->buffer, sizeof(flp->buffer)-1, flp->fp) == NULL)
{
flp->bdry = B_file;
tok = flp->cur = NULL;
return FALSE;
}
else
{
/* strip trailing whitespace, including \n */
for (p = flp->buffer+strlen(flp->buffer)-1
; p>flp->buffer && isspace(p[-1]); p--)
;
*p = '\0';
flp->lino++;
sor = p = flp->buffer;
}
break; /* try again for a token */
case ' ': /* whitespace */
case '\t':
p++;
break; /* try again for a token */
case '"': /* quoted token */
case '\'':
if (p != sor)
{
/* we have a quoted token: note and advance to its end */
tok = p;
p = strchr(p+1, *p);
if (p == NULL)
{
loglog(RC_LOG_SERIOUS, "\"%s\" line %d: unterminated string"
, flp->filename, flp->lino);
p = tok + strlen(tok);
}
else
{
p++; /* include delimiter in token */
}
/* remember token delimiter and replace with '\0' */
flp->under = *p;
*p = '\0';
flp->cur = p;
return TRUE;
}
/* FALL THROUGH */
default:
if (p != sor)
{
/* we seem to have a token: note and advance to its end */
tok = p;
if (p[0] == '0' && p[1] == 't')
{
/* 0t... token goes to end of line */
p += strlen(p);
}
else
{
/* "ordinary" token: up to whitespace or end of line */
do {
p++;
} while (*p != '\0' && !isspace(*p))
;
/* fudge to separate ':' from a preceding adjacent token */
if (p-1 > tok && p[-1] == ':')
p--;
}
/* remember token delimiter and replace with '\0' */
flp->under = *p;
*p = '\0';
flp->cur = p;
return TRUE;
}
/* we have a start-of-record: return it, deferring "real" token */
flp->bdry = B_record;
tok = NULL;
flp->under = *p;
flp->cur = p;
return FALSE;
}
}
}
/* ensures we are at a Record (or File) boundary, optionally warning if not */
bool
flushline(const char *m)
{
if (flp->bdry != B_none)
{
return TRUE;
}
else
{
if (m != NULL)
loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s", flp->filename, flp->lino, m);
do ; while (shift());
return FALSE;
}
}
+52
View File
@@ -0,0 +1,52 @@
/* lexer (lexical analyzer) for control files
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: lex.h,v 1.1 2004/03/15 20:35:28 as Exp $
*/
#define MAX_TOK_LEN 2048 /* includes terminal '\0' */
struct file_lex_position
{
int depth; /* how deeply we are nested */
const char *filename;
FILE *fp;
enum { B_none, B_record, B_file } bdry; /* current boundary */
int lino; /* line number in file */
char buffer[MAX_TOK_LEN + 1]; /* note: one extra char for our use (jamming '"') */
char *cur; /* cursor */
char under; /* except in shift(): character orignally at *cur */
struct file_lex_position *previous;
};
extern struct file_lex_position *flp;
extern bool lexopen(struct file_lex_position *new_flp, const char *name, bool optional);
extern void lexclose(void);
/* Token decoding: shift() loads the next token into tok.
* Iff a token starts at the left margin, it is considered
* to be the first in a record. We create a special condition,
* Record Boundary (analogous to EOF), just before such a token.
* We are unwilling to shift through a record boundary:
* it must be overridden first.
* Returns FALSE iff Record Boundary or EOF (i.e. no token);
* tok will then be NULL.
*/
extern char *tok;
#define tokeq(s) (streq(tok, (s)))
#define tokeqword(s) (strcasecmp(tok, (s)) == 0)
extern bool shift(void);
extern bool flushline(const char *m);
+90
View File
@@ -0,0 +1,90 @@
#ifndef __LINUX_NETLINK_H
#define __LINUX_NETLINK_H
#include <stdint.h>
#include <sys/socket.h> /* for sa_family_t */
#define NETLINK_ROUTE 0 /* Routing/device hook */
#define NETLINK_SKIP 1 /* Reserved for ENskip */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Firewalling hook */
#define NETLINK_TCPDIAG 4 /* TCP socket monitoring */
#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
#define NETLINK_XFRM 6 /* ipsec */
#define NETLINK_ARPD 8
#define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */
#define NETLINK_IP6_FW 13
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
#define NETLINK_TAPBASE 16 /* 16 to 31 are ethertap */
#define MAX_LINKS 32
struct sockaddr_nl
{
sa_family_t nl_family; /* AF_NETLINK */
unsigned short nl_pad; /* zero */
uint32_t nl_pid; /* process pid */
uint32_t nl_groups; /* multicast groups mask */
};
struct nlmsghdr
{
uint32_t nlmsg_len; /* Length of message including header */
uint16_t nlmsg_type; /* Message content */
uint16_t nlmsg_flags; /* Additional flags */
uint32_t nlmsg_seq; /* Sequence number */
uint32_t nlmsg_pid; /* Sending process PID */
};
/* Flags values */
#define NLM_F_REQUEST 1 /* It is request message. */
#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */
#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */
#define NLM_F_ECHO 8 /* Echo this request */
/* Modifiers to GET request */
#define NLM_F_ROOT 0x100 /* specify tree root */
#define NLM_F_MATCH 0x200 /* return all matching */
#define NLM_F_ATOMIC 0x400 /* atomic GET */
#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
/* Modifiers to NEW request */
#define NLM_F_REPLACE 0x100 /* Override existing */
#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
#define NLM_F_APPEND 0x800 /* Add to end of list */
/*
4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
4.4BSD CHANGE NLM_F_REPLACE
True CHANGE NLM_F_CREATE|NLM_F_REPLACE
Append NLM_F_CREATE
Check NLM_F_EXCL
*/
#define NLMSG_ALIGNTO 4
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
(struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
#define NLMSG_OK(nlh,len) ((len) > 0 && (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
(nlh)->nlmsg_len <= (len))
#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
#define NLMSG_NOOP 0x1 /* Nothing. */
#define NLMSG_ERROR 0x2 /* Error */
#define NLMSG_DONE 0x3 /* End of a dump */
#define NLMSG_OVERRUN 0x4 /* Data lost */
struct nlmsgerr
{
int error;
struct nlmsghdr msg;
};
#define NET_MAJOR 36 /* Major 36 is reserved for networking */
#endif /* __LINUX_NETLINK_H */
+562
View File
@@ -0,0 +1,562 @@
#ifndef __LINUX_RTNETLINK_H
#define __LINUX_RTNETLINK_H
#include "netlink.h"
#include <stdint.h>
#define RTNL_DEBUG 1
/****
* Routing/neighbour discovery messages.
****/
/* Types of messages */
#define RTM_BASE 0x10
#define RTM_NEWLINK (RTM_BASE+0)
#define RTM_DELLINK (RTM_BASE+1)
#define RTM_GETLINK (RTM_BASE+2)
#define RTM_SETLINK (RTM_BASE+3)
#define RTM_NEWADDR (RTM_BASE+4)
#define RTM_DELADDR (RTM_BASE+5)
#define RTM_GETADDR (RTM_BASE+6)
#define RTM_NEWROUTE (RTM_BASE+8)
#define RTM_DELROUTE (RTM_BASE+9)
#define RTM_GETROUTE (RTM_BASE+10)
#define RTM_NEWNEIGH (RTM_BASE+12)
#define RTM_DELNEIGH (RTM_BASE+13)
#define RTM_GETNEIGH (RTM_BASE+14)
#define RTM_NEWRULE (RTM_BASE+16)
#define RTM_DELRULE (RTM_BASE+17)
#define RTM_GETRULE (RTM_BASE+18)
#define RTM_NEWQDISC (RTM_BASE+20)
#define RTM_DELQDISC (RTM_BASE+21)
#define RTM_GETQDISC (RTM_BASE+22)
#define RTM_NEWTCLASS (RTM_BASE+24)
#define RTM_DELTCLASS (RTM_BASE+25)
#define RTM_GETTCLASS (RTM_BASE+26)
#define RTM_NEWTFILTER (RTM_BASE+28)
#define RTM_DELTFILTER (RTM_BASE+29)
#define RTM_GETTFILTER (RTM_BASE+30)
#define RTM_MAX (RTM_BASE+31)
/*
Generic structure for encapsulation optional route information.
It is reminiscent of sockaddr, but with sa_family replaced
with attribute type.
*/
struct rtattr
{
unsigned short rta_len;
unsigned short rta_type;
};
/* Macros to handle rtattributes */
#define RTA_ALIGNTO 4
#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
#define RTA_OK(rta,len) ((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
(rta)->rta_len <= (len))
#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
(struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
#define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
/******************************************************************************
* Definitions used in routing table administation.
****/
struct rtmsg
{
unsigned char rtm_family;
unsigned char rtm_dst_len;
unsigned char rtm_src_len;
unsigned char rtm_tos;
unsigned char rtm_table; /* Routing table id */
unsigned char rtm_protocol; /* Routing protocol; see below */
unsigned char rtm_scope; /* See below */
unsigned char rtm_type; /* See below */
unsigned rtm_flags;
};
/* rtm_type */
enum
{
RTN_UNSPEC,
RTN_UNICAST, /* Gateway or direct route */
RTN_LOCAL, /* Accept locally */
RTN_BROADCAST, /* Accept locally as broadcast,
send as broadcast */
RTN_ANYCAST, /* Accept locally as broadcast,
but send as unicast */
RTN_MULTICAST, /* Multicast route */
RTN_BLACKHOLE, /* Drop */
RTN_UNREACHABLE, /* Destination is unreachable */
RTN_PROHIBIT, /* Administratively prohibited */
RTN_THROW, /* Not in this table */
RTN_NAT, /* Translate this address */
RTN_XRESOLVE, /* Use external resolver */
};
#define RTN_MAX RTN_XRESOLVE
/* rtm_protocol */
#define RTPROT_UNSPEC 0
#define RTPROT_REDIRECT 1 /* Route installed by ICMP redirects;
not used by current IPv4 */
#define RTPROT_KERNEL 2 /* Route installed by kernel */
#define RTPROT_BOOT 3 /* Route installed during boot */
#define RTPROT_STATIC 4 /* Route installed by administrator */
/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
they just passed from user and back as is.
It will be used by hypothetical multiple routing daemons.
Note that protocol values should be standardized in order to
avoid conflicts.
*/
#define RTPROT_GATED 8 /* Apparently, GateD */
#define RTPROT_RA 9 /* RDISC/ND router advertisments */
#define RTPROT_MRT 10 /* Merit MRT */
#define RTPROT_ZEBRA 11 /* Zebra */
#define RTPROT_BIRD 12 /* BIRD */
#define RTPROT_DNROUTED 13 /* DECnet routing daemon */
/* rtm_scope
Really it is not scope, but sort of distance to the destination.
NOWHERE are reserved for not existing destinations, HOST is our
local addresses, LINK are destinations, located on directly attached
link and UNIVERSE is everywhere in the Universe.
Intermediate values are also possible f.e. interior routes
could be assigned a value between UNIVERSE and LINK.
*/
enum rt_scope_t
{
RT_SCOPE_UNIVERSE=0,
/* User defined values */
RT_SCOPE_SITE=200,
RT_SCOPE_LINK=253,
RT_SCOPE_HOST=254,
RT_SCOPE_NOWHERE=255
};
/* rtm_flags */
#define RTM_F_NOTIFY 0x100 /* Notify user of route change */
#define RTM_F_CLONED 0x200 /* This route is cloned */
#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */
/* Reserved table identifiers */
enum rt_class_t
{
RT_TABLE_UNSPEC=0,
/* User defined values */
RT_TABLE_DEFAULT=253,
RT_TABLE_MAIN=254,
RT_TABLE_LOCAL=255
};
#define RT_TABLE_MAX RT_TABLE_LOCAL
/* Routing message attributes */
enum rtattr_type_t
{
RTA_UNSPEC,
RTA_DST,
RTA_SRC,
RTA_IIF,
RTA_OIF,
RTA_GATEWAY,
RTA_PRIORITY,
RTA_PREFSRC,
RTA_METRICS,
RTA_MULTIPATH,
RTA_PROTOINFO,
RTA_FLOW,
RTA_CACHEINFO,
RTA_SESSION,
};
#define RTA_MAX RTA_SESSION
#define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg))))
#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg))
/* RTM_MULTIPATH --- array of struct rtnexthop.
*
* "struct rtnexthop" describres all necessary nexthop information,
* i.e. parameters of path to a destination via this nextop.
*
* At the moment it is impossible to set different prefsrc, mtu, window
* and rtt for different paths from multipath.
*/
struct rtnexthop
{
unsigned short rtnh_len;
unsigned char rtnh_flags;
unsigned char rtnh_hops;
int rtnh_ifindex;
};
/* rtnh_flags */
#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
#define RTNH_F_ONLINK 4 /* Gateway is forced on link */
/* Macros to handle hexthops */
#define RTNH_ALIGNTO 4
#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) )
#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \
((int)(rtnh)->rtnh_len) <= (len))
#define RTNH_NEXT(rtnh) ((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len)))
#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len))
#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len))
#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
/* RTM_CACHEINFO */
struct rta_cacheinfo
{
uint32_t rta_clntref;
uint32_t rta_lastuse;
int32_t rta_expires;
uint32_t rta_error;
uint32_t rta_used;
#define RTNETLINK_HAVE_PEERINFO 1
uint32_t rta_id;
uint32_t rta_ts;
uint32_t rta_tsage;
};
/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */
enum
{
RTAX_UNSPEC,
#define RTAX_UNSPEC RTAX_UNSPEC
RTAX_LOCK,
#define RTAX_LOCK RTAX_LOCK
RTAX_MTU,
#define RTAX_MTU RTAX_MTU
RTAX_WINDOW,
#define RTAX_WINDOW RTAX_WINDOW
RTAX_RTT,
#define RTAX_RTT RTAX_RTT
RTAX_RTTVAR,
#define RTAX_RTTVAR RTAX_RTTVAR
RTAX_SSTHRESH,
#define RTAX_SSTHRESH RTAX_SSTHRESH
RTAX_CWND,
#define RTAX_CWND RTAX_CWND
RTAX_ADVMSS,
#define RTAX_ADVMSS RTAX_ADVMSS
RTAX_REORDERING,
#define RTAX_REORDERING RTAX_REORDERING
};
#define RTAX_MAX RTAX_REORDERING
struct rta_session
{
uint8_t proto;
union {
struct {
uint16_t sport;
uint16_t dport;
} ports;
struct {
uint8_t type;
uint8_t code;
uint16_t ident;
} icmpt;
uint32_t spi;
} u;
};
/*********************************************************
* Interface address.
****/
struct ifaddrmsg
{
unsigned char ifa_family;
unsigned char ifa_prefixlen; /* The prefix length */
unsigned char ifa_flags; /* Flags */
unsigned char ifa_scope; /* See above */
int ifa_index; /* Link index */
};
enum
{
IFA_UNSPEC,
IFA_ADDRESS,
IFA_LOCAL,
IFA_LABEL,
IFA_BROADCAST,
IFA_ANYCAST,
IFA_CACHEINFO
};
#define IFA_MAX IFA_CACHEINFO
/* ifa_flags */
#define IFA_F_SECONDARY 0x01
#define IFA_F_TEMPORARY IFA_F_SECONDARY
#define IFA_F_DEPRECATED 0x20
#define IFA_F_TENTATIVE 0x40
#define IFA_F_PERMANENT 0x80
struct ifa_cacheinfo
{
int32_t ifa_prefered;
int32_t ifa_valid;
};
#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
/*
Important comment:
IFA_ADDRESS is prefix address, rather than local interface address.
It makes no difference for normally configured broadcast interfaces,
but for point-to-point IFA_ADDRESS is DESTINATION address,
local address is supplied in IFA_LOCAL attribute.
*/
/**************************************************************
* Neighbour discovery.
****/
struct ndmsg
{
unsigned char ndm_family;
unsigned char ndm_pad1;
unsigned short ndm_pad2;
int ndm_ifindex; /* Link index */
uint16_t ndm_state;
uint8_t ndm_flags;
uint8_t ndm_type;
};
enum
{
NDA_UNSPEC,
NDA_DST,
NDA_LLADDR,
NDA_CACHEINFO
};
#define NDA_MAX NDA_CACHEINFO
#define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
/*
* Neighbor Cache Entry Flags
*/
#define NTF_PROXY 0x08 /* == ATF_PUBL */
#define NTF_ROUTER 0x80
/*
* Neighbor Cache Entry States.
*/
#define NUD_INCOMPLETE 0x01
#define NUD_REACHABLE 0x02
#define NUD_STALE 0x04
#define NUD_DELAY 0x08
#define NUD_PROBE 0x10
#define NUD_FAILED 0x20
/* Dummy states */
#define NUD_NOARP 0x40
#define NUD_PERMANENT 0x80
#define NUD_NONE 0x00
struct nda_cacheinfo
{
uint32_t ndm_confirmed;
uint32_t ndm_used;
uint32_t ndm_updated;
uint32_t ndm_refcnt;
};
/****
* General form of address family dependent message.
****/
struct rtgenmsg
{
unsigned char rtgen_family;
};
/*****************************************************************
* Link layer specific messages.
****/
/* struct ifinfomsg
* passes link level specific information, not dependent
* on network protocol.
*/
struct ifinfomsg
{
unsigned char ifi_family;
unsigned char __ifi_pad;
unsigned short ifi_type; /* ARPHRD_* */
int ifi_index; /* Link index */
unsigned ifi_flags; /* IFF_* flags */
unsigned ifi_change; /* IFF_* change mask */
};
enum
{
IFLA_UNSPEC,
IFLA_ADDRESS,
IFLA_BROADCAST,
IFLA_IFNAME,
IFLA_MTU,
IFLA_LINK,
IFLA_QDISC,
IFLA_STATS,
IFLA_COST,
#define IFLA_COST IFLA_COST
IFLA_PRIORITY,
#define IFLA_PRIORITY IFLA_PRIORITY
IFLA_MASTER,
#define IFLA_MASTER IFLA_MASTER
IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
#define IFLA_WIRELESS IFLA_WIRELESS
};
#define IFLA_MAX IFLA_WIRELESS
#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
/* ifi_flags.
IFF_* flags.
The only change is:
IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
more not changeable by user. They describe link media
characteristics and set by device driver.
Comments:
- Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
- If neiher of these three flags are set;
the interface is NBMA.
- IFF_MULTICAST does not mean anything special:
multicasts can be used on all not-NBMA links.
IFF_MULTICAST means that this media uses special encapsulation
for multicast frames. Apparently, all IFF_POINTOPOINT and
IFF_BROADCAST devices are able to use multicasts too.
*/
/* IFLA_LINK.
For usual devices it is equal ifi_index.
If it is a "virtual interface" (f.e. tunnel), ifi_link
can point to real physical interface (f.e. for bandwidth calculations),
or maybe 0, what means, that real media is unknown (usual
for IPIP tunnels, when route to endpoint is allowed to change)
*/
/*****************************************************************
* Traffic control messages.
****/
struct tcmsg
{
unsigned char tcm_family;
unsigned char tcm__pad1;
unsigned short tcm__pad2;
int tcm_ifindex;
uint32_t tcm_handle;
uint32_t tcm_parent;
uint32_t tcm_info;
};
enum
{
TCA_UNSPEC,
TCA_KIND,
TCA_OPTIONS,
TCA_STATS,
TCA_XSTATS,
TCA_RATE,
};
#define TCA_MAX TCA_RATE
#define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg))))
#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg))
/* SUMMARY: maximal rtattr understood by kernel */
#define RTATTR_MAX RTA_MAX
/* RTnetlink multicast groups */
#define RTMGRP_LINK 1
#define RTMGRP_NOTIFY 2
#define RTMGRP_NEIGH 4
#define RTMGRP_TC 8
#define RTMGRP_IPV4_IFADDR 0x10
#define RTMGRP_IPV4_MROUTE 0x20
#define RTMGRP_IPV4_ROUTE 0x40
#define RTMGRP_IPV6_IFADDR 0x100
#define RTMGRP_IPV6_MROUTE 0x200
#define RTMGRP_IPV6_ROUTE 0x400
#define RTMGRP_DECnet_IFADDR 0x1000
#define RTMGRP_DECnet_ROUTE 0x4000
/* End of information exported to user level */
#endif /* __LINUX_RTNETLINK_H */
+233
View File
@@ -0,0 +1,233 @@
#ifndef _LINUX_XFRM_H
#define _LINUX_XFRM_H
#include <stdint.h>
/* All of the structures in this file may not change size as they are
* passed into the kernel from userspace via netlink sockets.
*/
/* Structure to encapsulate addresses. I do not want to use
* "standard" structure. My apologies.
*/
typedef union
{
uint32_t a4;
uint32_t a6[4];
} xfrm_address_t;
/* Ident of a specific xfrm_state. It is used on input to lookup
* the state by (spi,daddr,ah/esp) or to store information about
* spi, protocol and tunnel address on output.
*/
struct xfrm_id
{
xfrm_address_t daddr;
uint32_t spi;
uint8_t proto;
};
/* Selector, used as selector both on policy rules (SPD) and SAs. */
struct xfrm_selector
{
xfrm_address_t daddr;
xfrm_address_t saddr;
uint16_t dport;
uint16_t dport_mask;
uint16_t sport;
uint16_t sport_mask;
uint16_t family;
uint8_t prefixlen_d;
uint8_t prefixlen_s;
uint8_t proto;
int ifindex;
uid_t user;
};
#define XFRM_INF (~(uint64_t)0)
struct xfrm_lifetime_cfg
{
uint64_t soft_byte_limit;
uint64_t hard_byte_limit;
uint64_t soft_packet_limit;
uint64_t hard_packet_limit;
uint64_t soft_add_expires_seconds;
uint64_t hard_add_expires_seconds;
uint64_t soft_use_expires_seconds;
uint64_t hard_use_expires_seconds;
};
struct xfrm_lifetime_cur
{
uint64_t bytes;
uint64_t packets;
uint64_t add_time;
uint64_t use_time;
};
struct xfrm_replay_state
{
uint32_t oseq;
uint32_t seq;
uint32_t bitmap;
};
struct xfrm_algo {
char alg_name[64];
int alg_key_len; /* in bits */
char alg_key[0];
};
struct xfrm_stats {
uint32_t replay_window;
uint32_t replay;
uint32_t integrity_failed;
};
enum
{
XFRM_POLICY_IN = 0,
XFRM_POLICY_OUT = 1,
XFRM_POLICY_FWD = 2,
XFRM_POLICY_MAX = 3
};
enum
{
XFRM_SHARE_ANY, /* No limitations */
XFRM_SHARE_SESSION, /* For this session only */
XFRM_SHARE_USER, /* For this user only */
XFRM_SHARE_UNIQUE /* Use once */
};
/* Netlink configuration messages. */
#define XFRM_MSG_BASE 0x10
#define XFRM_MSG_NEWSA (XFRM_MSG_BASE + 0)
#define XFRM_MSG_DELSA (XFRM_MSG_BASE + 1)
#define XFRM_MSG_GETSA (XFRM_MSG_BASE + 2)
#define XFRM_MSG_NEWPOLICY (XFRM_MSG_BASE + 3)
#define XFRM_MSG_DELPOLICY (XFRM_MSG_BASE + 4)
#define XFRM_MSG_GETPOLICY (XFRM_MSG_BASE + 5)
#define XFRM_MSG_ALLOCSPI (XFRM_MSG_BASE + 6)
#define XFRM_MSG_ACQUIRE (XFRM_MSG_BASE + 7)
#define XFRM_MSG_EXPIRE (XFRM_MSG_BASE + 8)
#define XFRM_MSG_UPDPOLICY (XFRM_MSG_BASE + 9)
#define XFRM_MSG_UPDSA (XFRM_MSG_BASE + 10)
#define XFRM_MSG_POLEXPIRE (XFRM_MSG_BASE + 11)
#define XFRM_MSG_MAX (XFRM_MSG_POLEXPIRE+1)
struct xfrm_user_tmpl {
struct xfrm_id id;
uint16_t family;
xfrm_address_t saddr;
uint32_t reqid;
uint8_t mode;
uint8_t share;
uint8_t optional;
uint32_t aalgos;
uint32_t ealgos;
uint32_t calgos;
};
struct xfrm_encap_tmpl {
uint16_t encap_type;
uint16_t encap_sport;
uint16_t encap_dport;
xfrm_address_t encap_oa;
};
/* Netlink message attributes. */
enum xfrm_attr_type_t {
XFRMA_UNSPEC,
XFRMA_ALG_AUTH, /* struct xfrm_algo */
XFRMA_ALG_CRYPT, /* struct xfrm_algo */
XFRMA_ALG_COMP, /* struct xfrm_algo */
XFRMA_ENCAP, /* struct xfrm_algo + struct xfrm_encap_tmpl */
XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */
#define XFRMA_MAX XFRMA_TMPL
};
struct xfrm_usersa_info {
struct xfrm_selector sel;
struct xfrm_id id;
xfrm_address_t saddr;
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
struct xfrm_stats stats;
uint32_t seq;
uint32_t reqid;
uint16_t family;
uint8_t mode; /* 0=transport,1=tunnel */
uint8_t replay_window;
uint8_t flags;
#define XFRM_STATE_NOECN 1
};
struct xfrm_usersa_id {
xfrm_address_t daddr;
uint32_t spi;
uint16_t family;
uint8_t proto;
};
struct xfrm_userspi_info {
struct xfrm_usersa_info info;
uint32_t min;
uint32_t max;
};
struct xfrm_userpolicy_info {
struct xfrm_selector sel;
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
uint32_t priority;
uint32_t index;
uint8_t dir;
uint8_t action;
#define XFRM_POLICY_ALLOW 0
#define XFRM_POLICY_BLOCK 1
uint8_t flags;
#define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */
uint8_t share;
};
struct xfrm_userpolicy_id {
struct xfrm_selector sel;
uint32_t index;
uint8_t dir;
};
struct xfrm_user_acquire {
struct xfrm_id id;
xfrm_address_t saddr;
struct xfrm_selector sel;
struct xfrm_userpolicy_info policy;
uint32_t aalgos;
uint32_t ealgos;
uint32_t calgos;
uint32_t seq;
};
struct xfrm_user_expire {
struct xfrm_usersa_info state;
uint8_t hard;
};
struct xfrm_user_polexpire {
struct xfrm_userpolicy_info pol;
uint8_t hard;
};
#define XFRMGRP_ACQUIRE 1
#define XFRMGRP_EXPIRE 2
#endif /* _LINUX_XFRM_H */
+843
View File
@@ -0,0 +1,843 @@
/* error logging functions
* Copyright (C) 1997 Angelos D. Keromytis.
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: log.c,v 1.7 2005/07/11 18:33:45 as Exp $
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h> /* used only if MSG_NOSIGNAL not defined */
#include <sys/queue.h>
#include <libgen.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "server.h"
#include "state.h"
#include "connections.h"
#include "kernel.h"
#include "whack.h" /* needs connections.h */
#include "timer.h"
/* close one per-peer log */
static void perpeer_logclose(struct connection *c); /* forward */
bool
log_to_stderr = TRUE, /* should log go to stderr? */
log_to_syslog = TRUE, /* should log go to syslog? */
log_to_perpeer= FALSE; /* should log go to per-IP file? */
bool
logged_txt_warning = FALSE; /* should we complain about finding KEY? */
/* should we complain when we find no local id */
bool
logged_myid_fqdn_txt_warning = FALSE,
logged_myid_ip_txt_warning = FALSE,
logged_myid_fqdn_key_warning = FALSE,
logged_myid_ip_key_warning = FALSE;
/* may include trailing / */
const char *base_perpeer_logdir = PERPEERLOGDIR;
static int perpeer_count = 0;
/* from sys/queue.h */
static CIRCLEQ_HEAD(,connection) perpeer_list;
/* Context for logging.
*
* Global variables: must be carefully adjusted at transaction boundaries!
* If the context provides a whack file descriptor, messages
* should be copied to it -- see whack_log()
*/
int whack_log_fd = NULL_FD; /* only set during whack_handle() */
struct state *cur_state = NULL; /* current state, for diagnostics */
struct connection *cur_connection = NULL; /* current connection, for diagnostics */
const ip_address *cur_from = NULL; /* source of current current message */
u_int16_t cur_from_port; /* host order */
void
init_log(const char *program)
{
if (log_to_stderr)
setbuf(stderr, NULL);
if (log_to_syslog)
openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
CIRCLEQ_INIT(&perpeer_list);
}
void
close_peerlog(void)
{
/* end of circular queue is given by pointer to "HEAD"
* BUT if the queue is not initialized, this won't be true
* so we must guard by test perpeer_list.cqh_first != NULL
*/
if (perpeer_list.cqh_first != NULL)
while (perpeer_list.cqh_first != (void *)&perpeer_list)
perpeer_logclose(perpeer_list.cqh_first);
}
void
close_log(void)
{
if (log_to_syslog)
closelog();
close_peerlog();
}
/* Sanitize character string in situ: turns dangerous characters into \OOO.
* With a bit of work, we could use simpler reps for \\, \r, etc.,
* but this is only to protect against something that shouldn't be used.
* Truncate resulting string to what fits in buffer.
*/
static size_t
sanitize(char *buf, size_t size)
{
# define UGLY_WIDTH 4 /* width for ugly character: \OOO */
size_t len;
size_t added = 0;
char *p;
passert(size >= UGLY_WIDTH); /* need room to swing cat */
/* find right side of string to be sanitized and count
* number of columns to be added. Stop on end of string
* or lack of room for more result.
*/
for (p = buf; *p != '\0' && &p[added] < &buf[size - UGLY_WIDTH]; )
{
unsigned char c = *p++;
if (c == '\\' || !isprint(c))
added += UGLY_WIDTH - 1;
}
/* at this point, p points after last original character to be
* included. added is how many characters are added to sanitize.
* so p[added] will point after last sanitized character.
*/
p[added] = '\0';
len = &p[added] - buf;
/* scan backwards, copying characters to their new home
* and inserting the expansions for ugly characters.
* It is finished when no more shifting is required.
* This is a predecrement loop.
*/
while (added != 0)
{
char fmtd[UGLY_WIDTH + 1];
unsigned char c;
while ((c = *--p) != '\\' && isprint(c))
p[added] = c;
added -= UGLY_WIDTH - 1;
snprintf(fmtd, sizeof(fmtd), "\\%03o", c);
memcpy(p + added, fmtd, UGLY_WIDTH);
}
return len;
# undef UGLY_WIDTH
}
/* format a string for the log, with suitable prefixes.
* A format starting with ~ indicates that this is a reprocessing
* of the message, so prefixing and quoting is suppressed.
*/
static void
fmt_log(char *buf, size_t buf_len, const char *fmt, va_list ap)
{
bool reproc = *fmt == '~';
size_t ps;
struct connection *c = cur_state != NULL ? cur_state->st_connection
: cur_connection;
buf[0] = '\0';
if (reproc)
fmt++; /* ~ at start of format suppresses this prefix */
else if (c != NULL)
{
/* start with name of connection */
char *const be = buf + buf_len;
char *bp = buf;
snprintf(bp, be - bp, "\"%s\"", c->name);
bp += strlen(bp);
/* if it fits, put in any connection instance information */
if (be - bp > CONN_INST_BUF)
{
fmt_conn_instance(c, bp);
bp += strlen(bp);
}
if (cur_state != NULL)
{
/* state number */
snprintf(bp, be - bp, " #%lu", cur_state->st_serialno);
bp += strlen(bp);
}
snprintf(bp, be - bp, ": ");
}
else if (cur_from != NULL)
{
/* peer's IP address */
/* Note: must not use ip_str() because our caller might! */
char ab[ADDRTOT_BUF];
(void) addrtot(cur_from, 0, ab, sizeof(ab));
snprintf(buf, buf_len, "packet from %s:%u: "
, ab, (unsigned)cur_from_port);
}
ps = strlen(buf);
vsnprintf(buf + ps, buf_len - ps, fmt, ap);
if (!reproc)
(void)sanitize(buf, buf_len);
}
static void
perpeer_logclose(struct connection *c)
{
/* only free/close things if we had used them! */
if (c->log_file != NULL)
{
passert(perpeer_count > 0);
CIRCLEQ_REMOVE(&perpeer_list, c, log_link);
perpeer_count--;
fclose(c->log_file);
c->log_file=NULL;
}
}
void
perpeer_logfree(struct connection *c)
{
perpeer_logclose(c);
if (c->log_file_name != NULL)
{
pfree(c->log_file_name);
c->log_file_name = NULL;
c->log_file_err = FALSE;
}
}
/* open the per-peer log */
static void
open_peerlog(struct connection *c)
{
syslog(LOG_INFO, "opening log file for conn %s", c->name);
if (c->log_file_name == NULL)
{
char peername[ADDRTOT_BUF], dname[ADDRTOT_BUF];
int peernamelen, lf_len;
addrtot(&c->spd.that.host_addr, 'Q', peername, sizeof(peername));
peernamelen = strlen(peername);
/* copy IP address, turning : and . into / */
{
char c, *p, *q;
p = peername;
q = dname;
do {
c = *p++;
if (c == '.' || c == ':')
c = '/';
*q++ = c;
} while (c != '\0');
}
lf_len = peernamelen * 2
+ strlen(base_perpeer_logdir)
+ sizeof("//.log")
+ 1;
c->log_file_name = alloc_bytes(lf_len, "per-peer log file name");
fprintf(stderr, "base dir |%s| dname |%s| peername |%s|"
, base_perpeer_logdir, dname, peername);
snprintf(c->log_file_name, lf_len, "%s/%s/%s.log"
, base_perpeer_logdir, dname, peername);
syslog(LOG_DEBUG, "conn %s logfile is %s", c->name, c->log_file_name);
}
/* now open the file, creating directories if necessary */
{ /* create the directory */
char *dname;
int bpl_len = strlen(base_perpeer_logdir);
char *slashloc;
dname = clone_str(c->log_file_name, "temp copy of file name");
dname = dirname(dname);
if (access(dname, W_OK) != 0)
{
if (errno != ENOENT)
{
if (c->log_file_err)
{
syslog(LOG_CRIT, "can not write to %s: %s"
, dname, strerror(errno));
c->log_file_err = TRUE;
pfree(dname);
return;
}
}
/* directory does not exist, walk path creating dirs */
/* start at base_perpeer_logdir */
slashloc = dname + bpl_len;
slashloc++; /* since, by construction there is a slash
right there */
while (*slashloc != '\0')
{
char saveslash;
/* look for next slash */
while (*slashloc != '\0' && *slashloc != '/') slashloc++;
saveslash = *slashloc;
*slashloc = '\0';
if (mkdir(dname, 0750) != 0 && errno != EEXIST)
{
syslog(LOG_CRIT, "can not create dir %s: %s"
, dname, strerror(errno));
c->log_file_err = TRUE;
pfree(dname);
return;
}
syslog(LOG_DEBUG, "created new directory %s", dname);
*slashloc = saveslash;
slashloc++;
}
}
pfree(dname);
}
c->log_file = fopen(c->log_file_name, "a");
if (c->log_file == NULL)
{
if (c->log_file_err)
{
syslog(LOG_CRIT, "logging system can not open %s: %s"
, c->log_file_name, strerror(errno));
c->log_file_err = TRUE;
}
return;
}
/* look for a connection to close! */
while (perpeer_count >= MAX_PEERLOG_COUNT)
{
/* can not be NULL because perpeer_count > 0 */
passert(perpeer_list.cqh_last != (void *)&perpeer_list);
perpeer_logclose(perpeer_list.cqh_last);
}
/* insert this into the list */
CIRCLEQ_INSERT_HEAD(&perpeer_list, c, log_link);
passert(c->log_file != NULL);
perpeer_count++;
}
/* log a line to cur_connection's log */
static void
peerlog(const char *prefix, const char *m)
{
if (cur_connection == NULL)
{
/* we can not log it in this case. Oh well. */
return;
}
if (cur_connection->log_file == NULL)
{
open_peerlog(cur_connection);
}
/* despite our attempts above, we may not be able to open the file. */
if (cur_connection->log_file != NULL)
{
char datebuf[32];
time_t n;
struct tm *t;
time(&n);
t = localtime(&n);
strftime(datebuf, sizeof(datebuf), "%Y-%m-%d %T", t);
fprintf(cur_connection->log_file, "%s %s%s\n", datebuf, prefix, m);
/* now move it to the front of the list */
CIRCLEQ_REMOVE(&perpeer_list, cur_connection, log_link);
CIRCLEQ_INSERT_HEAD(&perpeer_list, cur_connection, log_link);
}
}
void
plog(const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
fmt_log(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "%s\n", m);
if (log_to_syslog)
syslog(LOG_WARNING, "%s", m);
if (log_to_perpeer)
peerlog("", m);
whack_log(RC_LOG, "~%s", m);
}
void
loglog(int mess_no, const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
fmt_log(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "%s\n", m);
if (log_to_syslog)
syslog(LOG_WARNING, "%s", m);
if (log_to_perpeer)
peerlog("", m);
whack_log(mess_no, "~%s", m);
}
void
log_errno_routine(int e, const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
fmt_log(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
if (log_to_syslog)
syslog(LOG_ERR, "ERROR: %s. Errno %d: %s", m, e, strerror(e));
if (log_to_perpeer)
{
peerlog(strerror(e), m);
}
whack_log(RC_LOG_SERIOUS
, "~ERROR: %s. Errno %d: %s", m, e, strerror(e));
}
void
exit_log(const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
fmt_log(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "FATAL ERROR: %s\n", m);
if (log_to_syslog)
syslog(LOG_ERR, "FATAL ERROR: %s", m);
if (log_to_perpeer)
peerlog("FATAL ERROR: ", m);
whack_log(RC_LOG_SERIOUS, "~FATAL ERROR: %s", m);
exit_pluto(1);
}
void
exit_log_errno_routine(int e, const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
fmt_log(m, sizeof(m), message, args);
va_end(args);
if (log_to_stderr)
fprintf(stderr, "FATAL ERROR: %s. Errno %d: %s\n", m, e, strerror(e));
if (log_to_syslog)
syslog(LOG_ERR, "FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
if (log_to_perpeer)
peerlog(strerror(e), m);
whack_log(RC_LOG_SERIOUS
, "~FATAL ERROR: %s. Errno %d: %s", m, e, strerror(e));
exit_pluto(1);
}
/* emit message to whack.
* form is "ddd statename text" where
* - ddd is a decimal status code (RC_*) as described in whack.h
* - text is a human-readable annotation
*/
#ifdef DEBUG
static volatile sig_atomic_t dying_breath = FALSE;
#endif
void
whack_log(int mess_no, const char *message, ...)
{
int wfd = whack_log_fd != NULL_FD ? whack_log_fd
: cur_state != NULL ? cur_state->st_whack_sock
: NULL_FD;
if (wfd != NULL_FD
#ifdef DEBUG
|| dying_breath
#endif
)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
int prelen = snprintf(m, sizeof(m), "%03d ", mess_no);
passert(prelen >= 0);
va_start(args, message);
fmt_log(m+prelen, sizeof(m)-prelen, message, args);
va_end(args);
#if DEBUG
if (dying_breath)
{
/* status output copied to log */
if (log_to_stderr)
fprintf(stderr, "%s\n", m + prelen);
if (log_to_syslog)
syslog(LOG_WARNING, "%s", m + prelen);
if (log_to_perpeer)
peerlog("", m);
}
#endif
if (wfd != NULL_FD)
{
/* write to whack socket, but suppress possible SIGPIPE */
size_t len = strlen(m);
#ifdef MSG_NOSIGNAL /* depends on version of glibc??? */
m[len] = '\n'; /* don't need NUL, do need NL */
(void) send(wfd, m, len + 1, MSG_NOSIGNAL);
#else /* !MSG_NOSIGNAL */
int r;
struct sigaction act
, oldact;
m[len] = '\n'; /* don't need NUL, do need NL */
act.sa_handler = SIG_IGN;
sigemptyset(&act.sa_mask);
act.sa_flags = 0; /* no nothing */
r = sigaction(SIGPIPE, &act, &oldact);
passert(r == 0);
(void) write(wfd, m, len + 1);
r = sigaction(SIGPIPE, &oldact, NULL);
passert(r == 0);
#endif /* !MSG_NOSIGNAL */
}
}
}
/* Build up a diagnostic in a static buffer.
* Although this would be a generally useful function, it is very
* hard to come up with a discipline that prevents different uses
* from interfering. It is intended that by limiting it to building
* diagnostics, we will avoid this problem.
* Juggling is performed to allow an argument to be a previous
* result: the new string may safely depend on the old one. This
* restriction is not checked in any way: violators will produce
* confusing results (without crashing!).
*/
char diag_space[sizeof(diag_space)];
err_t
builddiag(const char *fmt, ...)
{
static char diag_space[LOG_WIDTH]; /* longer messages will be truncated */
char t[sizeof(diag_space)]; /* build result here first */
va_list args;
va_start(args, fmt);
t[0] = '\0'; /* in case nothing terminates string */
vsnprintf(t, sizeof(t), fmt, args);
va_end(args);
strcpy(diag_space, t);
return diag_space;
}
/* Debugging message support */
#ifdef DEBUG
void
switch_fail(int n, const char *file_str, unsigned long line_no)
{
char buf[30];
snprintf(buf, sizeof(buf), "case %d unexpected", n);
passert_fail(buf, file_str, line_no);
}
void
passert_fail(const char *pred_str, const char *file_str, unsigned long line_no)
{
/* we will get a possibly unplanned prefix. Hope it works */
loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
if (!dying_breath)
{
dying_breath = TRUE;
show_status(TRUE, NULL);
}
abort(); /* exiting correctly doesn't always work */
}
void
pexpect_log(const char *pred_str, const char *file_str, unsigned long line_no)
{
/* we will get a possibly unplanned prefix. Hope it works */
loglog(RC_LOG_SERIOUS, "EXPECTATION FAILED at %s:%lu: %s", file_str, line_no, pred_str);
}
lset_t
base_debugging = DBG_NONE, /* default to reporting nothing */
cur_debugging = DBG_NONE;
void
extra_debugging(const struct connection *c)
{
if(c == NULL)
{
reset_debugging();
return;
}
if (c!= NULL && c->extra_debugging != 0)
{
plog("enabling for connection: %s"
, bitnamesof(debug_bit_names, c->extra_debugging & ~cur_debugging));
cur_debugging |= c->extra_debugging;
}
}
/* log a debugging message (prefixed by "| ") */
void
DBG_log(const char *message, ...)
{
va_list args;
char m[LOG_WIDTH]; /* longer messages will be truncated */
va_start(args, message);
vsnprintf(m, sizeof(m), message, args);
va_end(args);
(void)sanitize(m, sizeof(m));
if (log_to_stderr)
fprintf(stderr, "| %s\n", m);
if (log_to_syslog)
syslog(LOG_DEBUG, "| %s", m);
if (log_to_perpeer)
peerlog("| ", m);
}
/* dump raw bytes in hex to stderr (for lack of any better destination) */
void
DBG_dump(const char *label, const void *p, size_t len)
{
# define DUMP_LABEL_WIDTH 20 /* arbitrary modest boundary */
# define DUMP_WIDTH (4 * (1 + 4 * 3) + 1)
char buf[DUMP_LABEL_WIDTH + DUMP_WIDTH];
char *bp;
const unsigned char *cp = p;
bp = buf;
if (label != NULL && label[0] != '\0')
{
/* Handle the label. Care must be taken to avoid buffer overrun. */
size_t llen = strlen(label);
if (llen + 1 > sizeof(buf))
{
DBG_log("%s", label);
}
else
{
strcpy(buf, label);
if (buf[llen-1] == '\n')
{
buf[llen-1] = '\0'; /* get rid of newline */
DBG_log("%s", buf);
}
else if (llen < DUMP_LABEL_WIDTH)
{
bp = buf + llen;
}
else
{
DBG_log("%s", buf);
}
}
}
do {
int i, j;
for (i = 0; len!=0 && i!=4; i++)
{
*bp++ = ' ';
for (j = 0; len!=0 && j!=4; len--, j++)
{
static const char hexdig[] = "0123456789abcdef";
*bp++ = ' ';
*bp++ = hexdig[(*cp >> 4) & 0xF];
*bp++ = hexdig[*cp & 0xF];
cp++;
}
}
*bp = '\0';
DBG_log("%s", buf);
bp = buf;
} while (len != 0);
# undef DUMP_LABEL_WIDTH
# undef DUMP_WIDTH
}
#endif /* DEBUG */
void
show_status(bool all, const char *name)
{
if (all)
{
show_ifaces_status();
show_myid_status();
show_debug_status();
}
whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
show_connections_status(all, name);
whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
show_states_status(name);
#ifdef KLIPS
whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */
show_shunt_status();
#endif
}
/* ip_str: a simple to use variant of addrtot.
* It stores its result in a static buffer.
* This means that newer calls overwrite the storage of older calls.
* Note: this is not used in any of the logging functions, so their
* callers may use it.
*/
const char *
ip_str(const ip_address *src)
{
static char buf[ADDRTOT_BUF];
addrtot(src, 0, buf, sizeof(buf));
return buf;
}
/*
* a routine that attempts to schedule itself daily.
*
*/
void
daily_log_reset(void)
{
/* now perform actions */
logged_txt_warning = FALSE;
logged_myid_fqdn_txt_warning = FALSE;
logged_myid_ip_txt_warning = FALSE;
logged_myid_fqdn_key_warning = FALSE;
logged_myid_ip_key_warning = FALSE;
}
void
daily_log_event(void)
{
struct tm *ltime;
time_t n, interval;
/* attempt to schedule oneself to midnight, local time
* do this by getting seconds in the day, and delaying
* by 86400 - hour*3600+minutes*60+seconds.
*/
time(&n);
ltime = localtime(&n);
interval = (24 * 60 * 60)
- (ltime->tm_sec
+ ltime->tm_min * 60
+ ltime->tm_hour * 3600);
event_schedule(EVENT_LOG_DAILY, interval, NULL);
daily_log_reset();
}
/*
* Local Variables:
* c-basic-offset:4
* c-style: pluto
* End:
*/
+236
View File
@@ -0,0 +1,236 @@
/* logging definitions
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: log.h,v 1.4 2005/07/11 18:33:45 as Exp $
*/
#include <freeswan.h>
#define LOG_WIDTH 1024 /* roof of number of chars in log line */
#ifndef PERPERRLOGDIR
#define PERPERRLOGDIR "/var/log/pluto/peer"
#endif
/* our versions of assert: log result */
#ifdef DEBUG
extern void passert_fail(const char *pred_str
, const char *file_str, unsigned long line_no) NEVER_RETURNS;
extern void pexpect_log(const char *pred_str
, const char *file_str, unsigned long line_no);
# define impossible() passert_fail("impossible", __FILE__, __LINE__)
extern void switch_fail(int n
, const char *file_str, unsigned long line_no) NEVER_RETURNS;
# define bad_case(n) switch_fail((int) n, __FILE__, __LINE__)
# define passert(pred) { \
if (!(pred)) \
passert_fail(#pred, __FILE__, __LINE__); \
}
# define pexpect(pred) { \
if (!(pred)) \
pexpect_log(#pred, __FILE__, __LINE__); \
}
/* assert that an err_t is NULL; evaluate exactly once */
# define happy(x) { \
err_t ugh = x; \
if (ugh != NULL) \
passert_fail(ugh, __FILE__, __LINE__); \
}
#else /*!DEBUG*/
# define impossible() abort()
# define bad_case(n) abort()
# define passert(pred) { } /* do nothing */
# define happy(x) { (void) x; } /* evaluate non-judgementally */
#endif /*!DEBUG*/
extern bool
log_to_stderr, /* should log go to stderr? */
log_to_syslog, /* should log go to syslog? */
log_to_perpeer; /* should log go to per-IP file? */
extern const char *base_perpeer_logdir;
/* maximum number of files to keep open for per-peer log files */
#define MAX_PEERLOG_COUNT 16
/* Context for logging.
*
* Global variables: must be carefully adjusted at transaction boundaries!
* All are to be left in RESET condition and will be checked.
* There are several pairs of routines to set and reset them.
* If the context provides a whack file descriptor, messages
* should be copied to it -- see whack_log()
*/
extern int whack_log_fd; /* only set during whack_handle() */
extern struct state *cur_state; /* current state, for diagnostics */
extern struct connection *cur_connection; /* current connection, for diagnostics */
extern const ip_address *cur_from; /* source of current current message */
extern u_int16_t cur_from_port; /* host order */
#ifdef DEBUG
extern lset_t cur_debugging; /* current debugging level */
extern void extra_debugging(const struct connection *c);
# define reset_debugging() { cur_debugging = base_debugging; }
# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \
&& cur_state == NULL \
&& cur_connection == NULL \
&& cur_from == NULL \
&& cur_debugging == base_debugging)
#else /*!DEBUG*/
# define extra_debugging(c) { }
# define reset_debugging() { }
# define GLOBALS_ARE_RESET() (whack_log_fd == NULL_FD \
&& cur_state == NULL \
&& cur_connection == NULL \
&& cur_from == NULL)
#endif /*!DEBUG*/
#define reset_globals() { \
whack_log_fd = NULL_FD; \
cur_state = NULL; \
cur_from = NULL; \
reset_cur_connection(); \
}
#define set_cur_connection(c) { \
cur_connection = (c); \
extra_debugging(c); \
}
#define reset_cur_connection() { \
cur_connection = NULL; \
reset_debugging(); \
}
#define set_cur_state(s) { \
cur_state = (s); \
extra_debugging((s)->st_connection); \
}
#define reset_cur_state() { \
cur_state = NULL; \
reset_debugging(); \
}
extern void init_log(const char *program);
extern void close_log(void);
extern void plog(const char *message, ...) PRINTF_LIKE(1);
extern void exit_log(const char *message, ...) PRINTF_LIKE(1) NEVER_RETURNS;
/* close of all per-peer logging */
extern void close_peerlog(void);
/* free all per-peer log resources */
extern void perpeer_logfree(struct connection *c);
/* the following routines do a dance to capture errno before it is changed
* A call must doubly parenthesize the argument list (no varargs macros).
* The first argument must be "e", the local variable that captures errno.
*/
#define log_errno(a) { int e = errno; log_errno_routine a; }
extern void log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2);
#define exit_log_errno(a) { int e = errno; exit_log_errno_routine a; }
extern void exit_log_errno_routine(int e, const char *message, ...) PRINTF_LIKE(2) NEVER_RETURNS NEVER_RETURNS;
extern void whack_log(int mess_no, const char *message, ...) PRINTF_LIKE(2);
/* Log to both main log and whack log
* Much like log, actually, except for specifying mess_no.
*/
extern void loglog(int mess_no, const char *message, ...) PRINTF_LIKE(2);
/* show status, usually on whack log */
extern void show_status(bool all, const char *name);
/* Build up a diagnostic in a static buffer.
* Although this would be a generally useful function, it is very
* hard to come up with a discipline that prevents different uses
* from interfering. It is intended that by limiting it to building
* diagnostics, we will avoid this problem.
* Juggling is performed to allow an argument to be a previous
* result: the new string may safely depend on the old one. This
* restriction is not checked in any way: violators will produce
* confusing results (without crashing!).
*/
extern char diag_space[LOG_WIDTH]; /* output buffer, but can be occupied at call */
extern err_t builddiag(const char *fmt, ...) PRINTF_LIKE(1);
#ifdef DEBUG
extern lset_t base_debugging; /* bits selecting what to report */
#define DBGP(cond) (cur_debugging & (cond))
#define DBG(cond, action) { if (DBGP(cond)) { action ; } }
extern void DBG_log(const char *message, ...) PRINTF_LIKE(1);
extern void DBG_dump(const char *label, const void *p, size_t len);
#define DBG_dump_chunk(label, ch) DBG_dump(label, (ch).ptr, (ch).len)
#else /*!DEBUG*/
#define DBG(cond, action) { } /* do nothing */
#endif /*!DEBUG*/
#define DBG_cond_dump(cond, label, p, len) DBG(cond, DBG_dump(label, p, len))
#define DBG_cond_dump_chunk(cond, label, ch) DBG(cond, DBG_dump_chunk(label, ch))
/* ip_str: a simple to use variant of addrtot.
* It stores its result in a static buffer.
* This means that newer calls overwrite the storage of older calls.
* Note: this is not used in any of the logging functions, so their
* callers may use it.
*/
extern const char *ip_str(const ip_address *src);
/*
* call this routine to reset daily items.
*/
extern void daily_log_reset(void);
extern void daily_log_event(void);
/*
* some events are to be logged only occasionally.
*/
extern bool logged_txt_warning;
extern bool logged_myid_ip_txt_warning;
extern bool logged_myid_ip_key_warning;
extern bool logged_myid_fqdn_txt_warning;
extern bool logged_myid_fqdn_key_warning;
+237
View File
@@ -0,0 +1,237 @@
/* MD2C.C - RSA Data Security, Inc., MD2 message-digest algorithm
*/
/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
rights reserved.
License to copy and use this software is granted for
non-commercial Internet Privacy-Enhanced Mail provided that it is
identified as the "RSA Data Security, Inc. MD2 Message Digest
Algorithm" in all material mentioning or referencing this software
or this function.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#include "md2.h"
#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */
static void MD2Transform PROTO_LIST
((unsigned char [16], unsigned char [16], const unsigned char [16]));
#ifdef HAVEMEMCOPY
#include <memory.h>
#define MD2_memcpy memcpy
#define MD2_memset memset
#else
#ifdef HAVEBCOPY
#define MD2_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c))
#define MD2_memset(_a,_b,_c) memset((_a), '\0',(_c))
#else
static void MD2_memcpy PROTO_LIST ((POINTER, CONST_POINTER, unsigned int));
static void MD2_memset PROTO_LIST ((POINTER, int, unsigned int));
#endif
#endif
/* Permutation of 0..255 constructed from the digits of pi. It gives a
"random" nonlinear byte substitution operation.
*/
static unsigned char PI_SUBST[256] = {
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
31, 26, 219, 153, 141, 51, 159, 17, 131, 20
};
static const unsigned char *PADDING[] = {
(const unsigned char *)"",
(const unsigned char *)"\001",
(const unsigned char *)"\002\002",
(const unsigned char *)"\003\003\003",
(const unsigned char *)"\004\004\004\004",
(const unsigned char *)"\005\005\005\005\005",
(const unsigned char *)"\006\006\006\006\006\006",
(const unsigned char *)"\007\007\007\007\007\007\007",
(const unsigned char *)"\010\010\010\010\010\010\010\010",
(const unsigned char *)"\011\011\011\011\011\011\011\011\011",
(const unsigned char *)"\012\012\012\012\012\012\012\012\012\012",
(const unsigned char *)"\013\013\013\013\013\013\013\013\013\013\013",
(const unsigned char *)"\014\014\014\014\014\014\014\014\014\014\014\014",
(const unsigned char *)
"\015\015\015\015\015\015\015\015\015\015\015\015\015",
(const unsigned char *)
"\016\016\016\016\016\016\016\016\016\016\016\016\016\016",
(const unsigned char *)
"\017\017\017\017\017\017\017\017\017\017\017\017\017\017\017",
(const unsigned char *)
"\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020"
};
/* MD2 initialization. Begins an MD2 operation, writing a new context.
*/
void MD2Init (context)
MD2_CTX *context; /* context */
{
context->count = 0;
MD2_memset ((POINTER)context->state, 0, sizeof (context->state));
MD2_memset
((POINTER)context->checksum, 0, sizeof (context->checksum));
}
/* MD2 block update operation. Continues an MD2 message-digest
operation, processing another message block, and updating the
context.
*/
void MD2Update (context, input, inputLen)
MD2_CTX *context; /* context */
const unsigned char *input; /* input block */
unsigned int inputLen; /* length of input block */
{
unsigned int i, index, partLen;
/* Update number of bytes mod 16 */
index = context->count;
context->count = (index + inputLen) & 0xf;
partLen = 16 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen) {
MD2_memcpy
((POINTER)&context->buffer[index], (CONST_POINTER)input, partLen);
MD2Transform (context->state, context->checksum, context->buffer);
for (i = partLen; i + 15 < inputLen; i += 16)
MD2Transform (context->state, context->checksum, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD2_memcpy
((POINTER)&context->buffer[index], (CONST_POINTER)&input[i],
inputLen-i);
}
/* MD2 finalization. Ends an MD2 message-digest operation, writing the
message digest and zeroizing the context.
*/
void MD2Final (digest, context)
unsigned char digest[16]; /* message digest */
MD2_CTX *context; /* context */
{
unsigned int index, padLen;
/* Pad out to multiple of 16.
*/
index = context->count;
padLen = 16 - index;
MD2Update (context, PADDING[padLen], padLen);
/* Extend with checksum */
MD2Update (context, context->checksum, 16);
/* Store state in digest */
MD2_memcpy ((POINTER)digest, (POINTER)context->state, 16);
/* Zeroize sensitive information.
*/
MD2_memset ((POINTER)context, 0, sizeof (*context));
}
/* MD2 basic transformation. Transforms state and updates checksum
based on block.
*/
static void MD2Transform (state, checksum, block)
unsigned char state[16];
unsigned char checksum[16];
const unsigned char block[16];
{
unsigned int i, j, t;
unsigned char x[48];
/* Form encryption block from state, block, state ^ block.
*/
MD2_memcpy ((POINTER)x, (CONST_POINTER)state, 16);
MD2_memcpy ((POINTER)x+16, (CONST_POINTER)block, 16);
for (i = 0; i < 16; i++)
x[i+32] = state[i] ^ block[i];
/* Encrypt block (18 rounds).
*/
t = 0;
for (i = 0; i < 18; i++) {
for (j = 0; j < 48; j++)
t = x[j] ^= PI_SUBST[t];
t = (t + i) & 0xff;
}
/* Save new state */
MD2_memcpy ((POINTER)state, (POINTER)x, 16);
/* Update checksum.
*/
t = checksum[15];
for (i = 0; i < 16; i++)
t = checksum[i] ^= PI_SUBST[block[i] ^ t];
/* Zeroize sensitive information.
*/
MD2_memset ((POINTER)x, 0, sizeof (x));
}
#ifndef HAVEMEMCOPY
#ifndef HAVEBCOPY
/* Note: Replace "for loop" with standard memcpy if possible.
*/
static void MD2_memcpy (output, input, len)
POINTER output;
POINTER input;
unsigned int len;
{
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
/* Note: Replace "for loop" with standard memset if possible.
*/
static void MD2_memset (output, value, len)
POINTER output;
int value;
unsigned int len;
{
unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}
#endif
#endif
+72
View File
@@ -0,0 +1,72 @@
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
/* GLOBAL.H - RSAREF types and constants
*/
/* PROTOTYPES should be set to one if and only if the compiler supports
function argument prototyping.
The following makes PROTOTYPES default to 0 if it has not already
been defined with C compiler flags.
*/
#ifndef PROTOTYPES
#define PROTOTYPES 1
#endif
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
typedef const unsigned char *CONST_POINTER;
/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
typedef unsigned long int UINT4;
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
returns an empty list.
*/
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif
#endif
/* MD2.H - header file for MD2C.C
*/
/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
rights reserved.
License to copy and use this software is granted for
non-commercial Internet Privacy-Enhanced Mail provided that it is
identified as the "RSA Data Security, Inc. MD2 Message Digest
Algorithm" in all material mentioning or referencing this software
or this function.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/* MD2 context. */
typedef struct {
unsigned char state[16]; /* state */
unsigned char checksum[16]; /* checksum */
unsigned int count; /* number of bytes, modulo 16 */
unsigned char buffer[16]; /* input buffer */
} MD2_CTX;
void MD2Init PROTO_LIST ((MD2_CTX *));
void MD2Update PROTO_LIST
((MD2_CTX *, const unsigned char *, unsigned int));
void MD2Final PROTO_LIST ((unsigned char [16], MD2_CTX *));
#define _MD2_H_
+385
View File
@@ -0,0 +1,385 @@
/*
* The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
* changes to accomodate it in the kernel by ji.
* Minor changes to make 64 bit clean by Peter Onion (i.e. using u_int*_t).
*/
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/*
* Additions by JI
*
* HAVEMEMCOPY is defined if mem* routines are available
*
* HAVEHTON is defined if htons() and htonl() can be used
* for big/little endian conversions
*
*/
#include <stddef.h>
#include <string.h>
#include <sys/types.h> /* for u_int*_t */
#include <endian.h> /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */
#include "md5.h"
#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
#define MD5Transform _MD5Transform
static void MD5Transform PROTO_LIST ((UINT4 [4], const unsigned char [64]));
#if BYTE_ORDER == LITTLE_ENDIAN
#define Encode MD5_memcpy
#define Decode MD5_memcpy
#else
static void Encode PROTO_LIST
((unsigned char *, UINT4 *, unsigned int));
static void Decode PROTO_LIST
((UINT4 *, unsigned char *, unsigned int));
#endif
#ifdef HAVEMEMCOPY
#include <memory.h>
#define MD5_memcpy memcpy
#define MD5_memset memset
#else
#ifdef HAVEBCOPY
#define MD5_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c))
#define MD5_memset(_a,_b,_c) memset((_a), '\0',(_c))
#else
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
#endif
#endif
static unsigned char PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
/* F, G, H and I are basic MD5 functions.
*/
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { \
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define GG(a, b, c, d, x, s, ac) { \
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define HH(a, b, c, d, x, s, ac) { \
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
#define II(a, b, c, d, x, s, ac) { \
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
(a) = ROTATE_LEFT ((a), (s)); \
(a) += (b); \
}
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
void MD5Init (context)
MD5_CTX *context; /* context */
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the
context.
*/
void MD5Update (context, input, inputLen)
MD5_CTX *context; /* context */
const unsigned char *input; /* input block */
UINT4 inputLen; /* length of input block */
{
UINT4 i;
unsigned int index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += (inputLen << 3)) < (inputLen << 3))
context->count[1]++;
context->count[1] += (inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible. */
if (inputLen >= partLen) {
MD5_memcpy((POINTER)&context->buffer[index], (CONSTPOINTER)input, partLen);
MD5Transform (context->state, context->buffer);
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, &input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD5_memcpy((POINTER)&context->buffer[index], (CONSTPOINTER)&input[i], inputLen-i);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
void MD5Final (digest, context)
unsigned char digest[16]; /* message digest */
MD5_CTX *context; /* context */
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING, padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
if (digest != NULL) /* Bill Simpson's padding */
{
/* store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
}
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (state, block)
UINT4 state[4];
const unsigned char block[64];
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)x, 0, sizeof (x));
}
#if BYTE_ORDER != LITTLE_ENDIAN
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (output, input, len)
unsigned char *output;
UINT4 *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (output, input, len)
UINT4 *output;
unsigned char *input;
unsigned int len;
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
}
#endif
#ifndef HAVEMEMCOPY
#ifndef HAVEBCOPY
/* Note: Replace "for loop" with standard memcpy if possible.
*/
static void MD5_memcpy (output, input, len)
POINTER output;
POINTER input;
unsigned int len;
{
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
/* Note: Replace "for loop" with standard memset if possible.
*/
static void MD5_memset (output, value, len)
POINTER output;
int value;
unsigned int len;
{
unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}
#endif
#endif
+75
View File
@@ -0,0 +1,75 @@
#ifndef _GLOBAL_H_
#define _GLOBAL_H_
/* GLOBAL.H - RSAREF types and constants
*/
/* PROTOTYPES should be set to one if and only if the compiler supports
function argument prototyping.
The following makes PROTOTYPES default to 0 if it has not already
been defined with C compiler flags.
*/
#ifndef PROTOTYPES
#define PROTOTYPES 1
#endif
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
typedef const unsigned char *CONSTPOINTER;
/* UINT2 defines a two byte word */
typedef u_int16_t UINT2;
/* UINT4 defines a four byte word */
typedef u_int32_t UINT4;
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
returns an empty list.
*/
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif
#endif
/* MD5.H - header file for MD5C.C
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
void MD5Init PROTO_LIST ((MD5_CTX *));
void MD5Update PROTO_LIST
((MD5_CTX *, const unsigned char *, UINT4));
void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
#define _MD5_H_
+798
View File
@@ -0,0 +1,798 @@
/* Mode config related functions
* Copyright (C) 2001-2002 Colubris Networks
* Copyright (C) 2003 Sean Mathews - Nu Tech Software Solutions, inc.
* Copyright (C) 2003-2004 Xelerance Corporation
*
* 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: modecfg.c,v 1.6 2006/04/24 20:44:57 as Exp $
*
* This code originally written by Colubris Networks, Inc.
* Extraction of patch and porting to 1.99 codebases by Xelerance Corporation
* Porting to 2.x by Sean Mathews
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "state.h"
#include "demux.h"
#include "timer.h"
#include "ipsec_doi.h"
#include "log.h"
#include "md5.h"
#include "sha1.h"
#include "crypto.h"
#include "modecfg.h"
#include "whack.h"
/*
* Addresses assigned (usually via MODE_CONFIG) to the Initiator
*/
struct internal_addr
{
ip_address ipaddr;
ip_address dns[2];
ip_address wins[2];
};
/*
* Get inside IP address for a connection
*/
static void
get_internal_addresses(struct connection *c, struct internal_addr *ia)
{
zero(ia);
if (isanyaddr(&c->spd.that.host_srcip))
{
/* not defined in connection - fetch it from LDAP */
}
else
{
ia->ipaddr = c->spd.that.host_srcip;
}
}
/*
* Compute HASH of Mode Config.
*/
static size_t
mode_cfg_hash(u_char *dest, const u_char *start, const u_char *roof
, const struct state *st)
{
struct hmac_ctx ctx;
hmac_init_chunk(&ctx, st->st_oakley.hasher, st->st_skeyid_a);
hmac_update(&ctx, (const u_char *) &st->st_msgid, sizeof(st->st_msgid));
hmac_update(&ctx, start, roof-start);
hmac_final(dest, &ctx);
DBG(DBG_CRYPT,
DBG_log("MODE CFG: HASH computed:");
DBG_dump("", dest, ctx.hmac_digest_size)
)
return ctx.hmac_digest_size;
}
/* Mode Config Reply
* Generates a reply stream containing Mode Config information (eg: IP, DNS, WINS)
*/
stf_status modecfg_resp(struct state *st
, u_int resp
, pb_stream *rbody
, u_int16_t replytype
, bool hackthat
, u_int16_t ap_id)
{
u_char *r_hash_start,*r_hashval;
/* START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_ATTR); */
{
pb_stream hash_pbs;
int np = ISAKMP_NEXT_ATTR;
if (!out_generic(np, &isakmp_hash_desc, rbody, &hash_pbs))
return STF_INTERNAL_ERROR;
r_hashval = hash_pbs.cur; /* remember where to plant value */
if (!out_zero(st->st_oakley.hasher->hash_digest_size, &hash_pbs, "HASH"))
return STF_INTERNAL_ERROR;
close_output_pbs(&hash_pbs);
r_hash_start = (rbody)->cur; /* hash from after HASH payload */
}
/* ATTR out */
{
struct isakmp_mode_attr attrh;
struct isakmp_attribute attr;
pb_stream strattr,attrval;
int attr_type;
struct internal_addr ia;
int dns_idx, wins_idx;
bool dont_advance;
attrh.isama_np = ISAKMP_NEXT_NONE;
attrh.isama_type = replytype;
attrh.isama_identifier = ap_id;
if (!out_struct(&attrh, &isakmp_attr_desc, rbody, &strattr))
return STF_INTERNAL_ERROR;
get_internal_addresses(st->st_connection, &ia);
if (!isanyaddr(&ia.dns[0])) /* We got DNS addresses, answer with those */
resp |= LELEM(INTERNAL_IP4_DNS);
else
resp &= ~LELEM(INTERNAL_IP4_DNS);
if (!isanyaddr(&ia.wins[0])) /* We got WINS addresses, answer with those */
resp |= LELEM(INTERNAL_IP4_NBNS);
else
resp &= ~LELEM(INTERNAL_IP4_NBNS);
if (hackthat)
{
if (memcmp(&st->st_connection->spd.that.client.addr
,&ia.ipaddr
,sizeof(ia.ipaddr)) != 0)
{
/* Make the Internal IP address and Netmask
* as that client address
*/
st->st_connection->spd.that.client.addr = ia.ipaddr;
st->st_connection->spd.that.client.maskbits = 32;
st->st_connection->spd.that.has_client = TRUE;
}
}
attr_type = 0;
dns_idx = 0;
wins_idx = 0;
while (resp != 0)
{
dont_advance = FALSE;
if (resp & 1)
{
const u_char *byte_ptr;
u_int len;
/* ISAKMP attr out */
attr.isaat_af_type = attr_type | ISAKMP_ATTR_AF_TLV;
out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, &attrval);
switch (attr_type)
{
case INTERNAL_IP4_ADDRESS:
{
char srcip[ADDRTOT_BUF];
addrtot(&ia.ipaddr, 0, srcip, sizeof(srcip));
plog("assigning virtual IP source address %s", srcip);
len = addrbytesptr(&ia.ipaddr, &byte_ptr);
out_raw(byte_ptr,len,&attrval,"IP4_addr");
}
break;
case INTERNAL_IP4_NETMASK:
{
u_int mask;
#if 0
char mask[4],bits[8]={0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe};
int t,m=st->st_connection->that.host_addr.maskbit;
for (t=0; t<4; t++)
{
if (m < 8)
mask[t] = bits[m];
else
mask[t] = 0xff;
m -= 8;
}
#endif
if (st->st_connection->spd.this.client.maskbits == 0)
mask = 0;
else
mask = 0xffffffff * 1;
out_raw(&mask,4,&attrval,"IP4_mask");
}
break;
case INTERNAL_IP4_SUBNET:
{
char mask[4];
char bits[8] = {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe};
int t;
int m = st->st_connection->spd.this.client.maskbits;
for (t = 0; t < 4; t++)
{
if (m < 8)
mask[t] = bits[m];
else
mask[t] = 0xff;
m -= 8;
if (m < 0)
m = 0;
}
len = addrbytesptr(&st->st_connection->spd.this.client.addr, &byte_ptr);
out_raw(byte_ptr,len,&attrval,"IP4_subnet");
out_raw(mask,sizeof(mask),&attrval,"IP4_submsk");
}
break;
case INTERNAL_IP4_DNS:
len = addrbytesptr(&ia.dns[dns_idx++], &byte_ptr);
out_raw(byte_ptr,len,&attrval,"IP4_dns");
if (dns_idx < 2 && !isanyaddr(&ia.dns[dns_idx]))
{
dont_advance = TRUE;
}
break;
case INTERNAL_IP4_NBNS:
len = addrbytesptr(&ia.wins[wins_idx++], &byte_ptr);
out_raw(byte_ptr,len,&attrval,"IP4_wins");
if (wins_idx < 2 && !isanyaddr(&ia.wins[wins_idx]))
{
dont_advance = TRUE;
}
break;
default:
plog("attempt to send unsupported mode cfg attribute %s."
, enum_show(&modecfg_attr_names, attr_type));
break;
}
close_output_pbs(&attrval);
}
if (!dont_advance)
{
attr_type++;
resp >>= 1;
}
}
close_message(&strattr);
}
mode_cfg_hash(r_hashval,r_hash_start,rbody->cur,st);
close_message(rbody);
encrypt_message(rbody, st);
return STF_OK;
}
/* Set MODE_CONFIG data to client.
* Pack IP Addresses, DNS, etc... and ship
*/
stf_status modecfg_send_set(struct state *st)
{
pb_stream reply,rbody;
char buf[256];
/* set up reply */
init_pbs(&reply, buf, sizeof(buf), "ModecfgR1");
st->st_state = STATE_MODE_CFG_R1;
/* HDR out */
{
struct isakmp_hdr hdr;
zero(&hdr); /* default to 0 */
hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
hdr.isa_np = ISAKMP_NEXT_HASH;
hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG;
hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
hdr.isa_msgid = st->st_msgid;
if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
{
return STF_INTERNAL_ERROR;
}
}
#define MODECFG_SET_ITEM ( LELEM(INTERNAL_IP4_ADDRESS) | LELEM(INTERNAL_IP4_SUBNET) | LELEM(INTERNAL_IP4_NBNS) | LELEM(INTERNAL_IP4_DNS) )
modecfg_resp(st, MODECFG_SET_ITEM
, &rbody
, ISAKMP_CFG_SET
, TRUE
, 0/* XXX ID */);
#undef MODECFG_SET_ITEM
clonetochunk(st->st_tpacket, reply.start
, pbs_offset(&reply), "ModeCfg set");
/* Transmit */
send_packet(st, "ModeCfg set");
/* RETRANSMIT if Main, SA_REPLACE if Aggressive */
if (st->st_event->ev_type != EVENT_RETRANSMIT
&& st->st_event->ev_type != EVENT_NULL)
{
delete_event(st);
event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0, st);
}
return STF_OK;
}
/* Set MODE_CONFIG data to client.
* Pack IP Addresses, DNS, etc... and ship
*/
stf_status
modecfg_start_set(struct state *st)
{
if (st->st_msgid == 0)
{
/* pick a new message id */
st->st_msgid = generate_msgid(st);
}
st->st_modecfg.vars_set = TRUE;
return modecfg_send_set(st);
}
/*
* Send modecfg IP address request (IP4 address)
*/
stf_status
modecfg_send_request(struct state *st)
{
pb_stream reply;
pb_stream rbody;
char buf[256];
u_char *r_hash_start,*r_hashval;
/* set up reply */
init_pbs(&reply, buf, sizeof(buf), "modecfg_buf");
plog("sending ModeCfg request");
/* this is the beginning of a new exchange */
st->st_msgid = generate_msgid(st);
st->st_state = STATE_MODE_CFG_I1;
/* HDR out */
{
struct isakmp_hdr hdr;
zero(&hdr); /* default to 0 */
hdr.isa_version = ISAKMP_MAJOR_VERSION << ISA_MAJ_SHIFT | ISAKMP_MINOR_VERSION;
hdr.isa_np = ISAKMP_NEXT_HASH;
hdr.isa_xchg = ISAKMP_XCHG_MODE_CFG;
hdr.isa_flags = ISAKMP_FLAG_ENCRYPTION;
memcpy(hdr.isa_icookie, st->st_icookie, COOKIE_SIZE);
memcpy(hdr.isa_rcookie, st->st_rcookie, COOKIE_SIZE);
hdr.isa_msgid = st->st_msgid;
if (!out_struct(&hdr, &isakmp_hdr_desc, &reply, &rbody))
{
return STF_INTERNAL_ERROR;
}
}
START_HASH_PAYLOAD(rbody, ISAKMP_NEXT_ATTR);
/* ATTR out */
{
struct isakmp_mode_attr attrh;
struct isakmp_attribute attr;
pb_stream strattr;
attrh.isama_np = ISAKMP_NEXT_NONE;
attrh.isama_type = ISAKMP_CFG_REQUEST;
attrh.isama_identifier = 0;
if (!out_struct(&attrh, &isakmp_attr_desc, &rbody, &strattr))
return STF_INTERNAL_ERROR;
/* ISAKMP attr out (ipv4) */
attr.isaat_af_type = INTERNAL_IP4_ADDRESS;
attr.isaat_lv = 0;
out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, NULL);
/* ISAKMP attr out (netmask) */
attr.isaat_af_type = INTERNAL_IP4_NETMASK;
attr.isaat_lv = 0;
out_struct(&attr, &isakmp_modecfg_attribute_desc, &strattr, NULL);
close_message(&strattr);
}
mode_cfg_hash(r_hashval,r_hash_start,rbody.cur,st);
close_message(&rbody);
close_output_pbs(&reply);
init_phase2_iv(st, &st->st_msgid);
encrypt_message(&rbody, st);
clonetochunk(st->st_tpacket, reply.start, pbs_offset(&reply)
, "modecfg: req");
/* Transmit */
send_packet(st, "modecfg: req");
/* RETRANSMIT if Main, SA_REPLACE if Aggressive */
if (st->st_event->ev_type != EVENT_RETRANSMIT)
{
delete_event(st);
event_schedule(EVENT_RETRANSMIT, EVENT_RETRANSMIT_DELAY_0 * 3, st);
}
st->st_modecfg.started = TRUE;
return STF_OK;
}
/*
* parse a modecfg attribute payload
*/
static stf_status
modecfg_parse_attributes(pb_stream *attrs, u_int *set)
{
struct isakmp_attribute attr;
pb_stream strattr;
while (pbs_left(attrs) > sizeof(struct isakmp_attribute))
{
if (!in_struct(&attr, &isakmp_modecfg_attribute_desc, attrs, &strattr))
{
int len = (attr.isaat_af_type & 0x8000)? 4 : attr.isaat_lv;
if (len < 4)
{
plog("Attribute was too short: %d", len);
return STF_FAIL;
}
attrs->cur += len;
}
switch (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )
{
case INTERNAL_IP4_ADDRESS:
case INTERNAL_IP4_NETMASK:
case INTERNAL_IP4_DNS:
case INTERNAL_IP4_SUBNET:
case INTERNAL_IP4_NBNS:
*set |= LELEM(attr.isaat_af_type);
break;
default:
plog("unsupported mode cfg attribute %s received."
, enum_show(&modecfg_attr_names
, attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK ));
break;
}
}
return STF_OK;
}
/* STATE_MODE_CFG_R0:
* HDR*, HASH, ATTR(REQ=IP) --> HDR*, HASH, ATTR(REPLY=IP)
*
* This state occurs both in the responder and in the initiator.
*
* In the responding server, it occurs when the client *asks* for an IP
* address or other information.
*
* Otherwise, it occurs in the initiator when the server sends a challenge
* a set, or has a reply to our request.
*/
stf_status
modecfg_inR0(struct msg_digest *md)
{
struct state *const st = md->st;
struct payload_digest *p;
stf_status stat;
plog("received ModeCfg request");
st->st_msgid = md->hdr.isa_msgid;
CHECK_QUICK_HASH(md, mode_cfg_hash(hash_val
,hash_pbs->roof
, md->message_pbs.roof, st)
, "MODECFG-HASH", "MODE R0");
/* process the MODECFG payloads therein */
for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
{
u_int set_modecfg_attrs = LEMPTY;
switch (p->payload.attribute.isama_type)
{
default:
plog("Expecting ISAKMP_CFG_REQUEST, got %s instead (ignored)."
, enum_name(&attr_msg_type_names
, p->payload.attribute.isama_type));
stat = modecfg_parse_attributes(&p->pbs, &set_modecfg_attrs);
if (stat != STF_OK)
return stat;
break;
case ISAKMP_CFG_REQUEST:
stat = modecfg_parse_attributes(&p->pbs, &set_modecfg_attrs);
if (stat != STF_OK)
return stat;
stat = modecfg_resp(st, set_modecfg_attrs
,&md->rbody
,ISAKMP_CFG_REPLY
,TRUE
,p->payload.attribute.isama_identifier);
if (stat != STF_OK)
{
/* notification payload - not exactly the right choice, but okay */
md->note = CERTIFICATE_UNAVAILABLE;
return stat;
}
/* they asked us, we responded, msgid is done */
st->st_msgid = 0;
}
}
return STF_OK;
}
/* STATE_MODE_CFG_R2:
* HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK)
*
* used in server push mode, on the client (initiator).
*/
static stf_status
modecfg_inI2(struct msg_digest *md)
{
struct state *const st = md->st;
pb_stream *attrs = &md->chain[ISAKMP_NEXT_ATTR]->pbs;
int resp = LEMPTY;
stf_status stat;
struct payload_digest *p;
u_int16_t isama_id = 0;
st->st_msgid = md->hdr.isa_msgid;
CHECK_QUICK_HASH(md
, mode_cfg_hash(hash_val
,hash_pbs->roof
, md->message_pbs.roof
, st)
, "MODECFG-HASH", "MODE R1");
for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
{
struct isakmp_attribute attr;
pb_stream strattr;
isama_id = p->payload.attribute.isama_identifier;
if (p->payload.attribute.isama_type != ISAKMP_CFG_SET)
{
plog("Expecting MODE_CFG_SET, got %x instead."
,md->chain[ISAKMP_NEXT_ATTR]->payload.attribute.isama_type);
return STF_IGNORE;
}
/* CHECK that SET has been received. */
while (pbs_left(attrs) > sizeof(struct isakmp_attribute))
{
if (!in_struct(&attr, &isakmp_modecfg_attribute_desc
, attrs, &strattr))
{
int len;
/* Skip unknown */
if (attr.isaat_af_type & 0x8000)
len = 4;
else
len = attr.isaat_lv;
if (len < 4)
{
plog("Attribute was too short: %d", len);
return STF_FAIL;
}
attrs->cur += len;
}
switch (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )
{
case INTERNAL_IP4_ADDRESS:
{
struct connection *c = st->st_connection;
ip_address a;
u_int32_t *ap = (u_int32_t *)(strattr.cur);
a.u.v4.sin_family = AF_INET;
memcpy(&a.u.v4.sin_addr.s_addr, ap
, sizeof(a.u.v4.sin_addr.s_addr));
if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
|| isanyaddr(&c->spd.this.host_srcip))
{
char srcip[ADDRTOT_BUF];
c->spd.this.host_srcip = a;
addrtot(&a, 0, srcip, sizeof(srcip));
plog("setting virtual IP source address to %s", srcip);
}
/* setting client subnet as srcip/32 */
addrtosubnet(&a, &c->spd.this.client);
c->spd.this.has_client = TRUE;
}
resp |= LELEM(attr.isaat_af_type);
break;
case INTERNAL_IP4_NETMASK:
case INTERNAL_IP4_DNS:
case INTERNAL_IP4_SUBNET:
case INTERNAL_IP4_NBNS:
resp |= LELEM(attr.isaat_af_type);
break;
default:
plog("unsupported mode cfg attribute %s received."
, enum_show(&modecfg_attr_names, (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )));
break;
}
}
}
/* ack things */
stat = modecfg_resp(st, resp
,&md->rbody
,ISAKMP_CFG_ACK
,FALSE
,isama_id);
if (stat != STF_OK)
{
/* notification payload - not exactly the right choice, but okay */
md->note = CERTIFICATE_UNAVAILABLE;
return stat;
}
/*
* we are done with this exchange, clear things so
* that we can start phase 2 properly
*/
st->st_msgid = 0;
if (resp)
{
st->st_modecfg.vars_set = TRUE;
}
return STF_OK;
}
/* STATE_MODE_CFG_R1:
* HDR*, HASH, ATTR(SET=IP) --> HDR*, HASH, ATTR(ACK,OK)
*/
stf_status
modecfg_inR1(struct msg_digest *md)
{
struct state *const st = md->st;
pb_stream *attrs = &md->chain[ISAKMP_NEXT_ATTR]->pbs;
int set_modecfg_attrs = LEMPTY;
stf_status stat;
struct payload_digest *p;
plog("parsing ModeCfg reply");
st->st_msgid = md->hdr.isa_msgid;
CHECK_QUICK_HASH(md, mode_cfg_hash(hash_val,hash_pbs->roof, md->message_pbs.roof, st)
, "MODECFG-HASH", "MODE R1");
/* process the MODECFG payloads therein */
for (p = md->chain[ISAKMP_NEXT_ATTR]; p != NULL; p = p->next)
{
struct isakmp_attribute attr;
pb_stream strattr;
attrs = &p->pbs;
switch (p->payload.attribute.isama_type)
{
default:
{
plog("Expecting MODE_CFG_ACK, got %x instead."
,md->chain[ISAKMP_NEXT_ATTR]->payload.attribute.isama_type);
return STF_IGNORE;
}
break;
case ISAKMP_CFG_ACK:
/* CHECK that ACK has been received. */
stat = modecfg_parse_attributes(attrs, &set_modecfg_attrs);
if (stat != STF_OK)
return stat;
break;
case ISAKMP_CFG_REPLY:
while (pbs_left(attrs) > sizeof(struct isakmp_attribute))
{
if (!in_struct(&attr, &isakmp_modecfg_attribute_desc
, attrs, &strattr))
{
/* Skip unknown */
int len;
if (attr.isaat_af_type & 0x8000)
len = 4;
else
len = attr.isaat_lv;
if (len < 4)
{
plog("Attribute was too short: %d", len);
return STF_FAIL;
}
attrs->cur += len;
}
switch (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )
{
case INTERNAL_IP4_ADDRESS:
{
struct connection *c = st->st_connection;
ip_address a;
u_int32_t *ap = (u_int32_t *)(strattr.cur);
a.u.v4.sin_family = AF_INET;
memcpy(&a.u.v4.sin_addr.s_addr, ap
, sizeof(a.u.v4.sin_addr.s_addr));
if (addrbytesptr(&c->spd.this.host_srcip, NULL) == 0
|| isanyaddr(&c->spd.this.host_srcip))
{
char srcip[ADDRTOT_BUF];
c->spd.this.host_srcip = a;
addrtot(&a, 0, srcip, sizeof(srcip));
plog("setting virtual IP source address to %s", srcip);
}
/* setting client subnet as srcip/32 */
addrtosubnet(&a, &c->spd.this.client);
setportof(0, &c->spd.this.client.addr);
c->spd.this.has_client = TRUE;
}
/* fall through to set attribute flage */
case INTERNAL_IP4_NETMASK:
case INTERNAL_IP4_DNS:
case INTERNAL_IP4_SUBNET:
case INTERNAL_IP4_NBNS:
set_modecfg_attrs |= LELEM(attr.isaat_af_type);
break;
default:
plog("unsupported mode cfg attribute %s received."
, enum_show(&modecfg_attr_names
, (attr.isaat_af_type & ISAKMP_ATTR_RTYPE_MASK )));
break;
}
}
break;
}
}
/* we are done with this exchange, clear things so that we can start phase 2 properly */
st->st_msgid = 0;
if (set_modecfg_attrs)
{
st->st_modecfg.vars_set = TRUE;
}
return STF_OK;
}
+33
View File
@@ -0,0 +1,33 @@
/* Mode Config related functions
* Copyright (C) 2001-2002 Colubris Networks
* Copyright (C) 2003-2004 Xelerance Corporation
*
* 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: modecfg.h,v 1.1 2005/01/06 22:10:15 as Exp $
*/
struct state;
stf_status modecfg_resp(struct state *st
, u_int resp
, pb_stream *s, u_int16_t cmd
, bool hackthat, u_int16_t id);
stf_status modecfg_send_set(struct state *st);
extern stf_status modecfg_start_set(struct state *st);
/* Mode Config States */
extern stf_status modecfg_inR0(struct msg_digest *md);
extern stf_status modecfg_inR1(struct msg_digest *md);
extern stf_status modecfg_send_request(struct state *st);
+70
View File
@@ -0,0 +1,70 @@
/* some multiprecision utilities
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: mp_defs.c,v 1.1 2006/01/05 12:37:11 as Exp $
*/
#include <freeswan.h>
#include "constants.h"
#include "defs.h"
#include "mp_defs.h"
#include "log.h"
/* Convert MP_INT to network form (binary octets, big-endian).
* We do the malloc; caller must eventually do free.
*/
chunk_t
mpz_to_n(const MP_INT *mp, size_t bytes)
{
chunk_t r;
MP_INT temp1, temp2;
int i;
r.len = bytes;
r.ptr = alloc_bytes(r.len, "host representation of large integer");
mpz_init(&temp1);
mpz_init(&temp2);
mpz_set(&temp1, mp);
for (i = r.len-1; i >= 0; i--)
{
r.ptr[i] = mpz_mdivmod_ui(&temp2, NULL, &temp1, 1 << BITS_PER_BYTE);
mpz_set(&temp1, &temp2);
}
passert(mpz_sgn(&temp1) == 0); /* we must have done all the bits */
mpz_clear(&temp1);
mpz_clear(&temp2);
return r;
}
/* Convert network form (binary bytes, big-endian) to MP_INT.
* The *mp must not be previously mpz_inited.
*/
void
n_to_mpz(MP_INT *mp, const u_char *nbytes, size_t nlen)
{
size_t i;
mpz_init_set_ui(mp, 0);
for (i = 0; i != nlen; i++)
{
mpz_mul_ui(mp, mp, 1 << BITS_PER_BYTE);
mpz_add_ui(mp, mp, nbytes[i]);
}
}
+36
View File
@@ -0,0 +1,36 @@
/* some multiprecision utilities
* Copyright (C) 1997 Angelos D. Keromytis.
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
*
* 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: mp_defs.h,v 1.2 2006/01/06 11:40:45 as Exp $
*/
#ifndef _MP_DEFS_H
#define _MP_DEFS_H
#include <gmp.h>
#include "defs.h"
extern void n_to_mpz(MP_INT *mp, const u_char *nbytes, size_t nlen);
extern chunk_t mpz_to_n(const MP_INT *mp, size_t bytes);
/* var := mod(base ** exp, mod), ensuring var is mpz_inited */
#define mpz_init_powm(flag, var, base, exp, mod) { \
if (!(flag)) \
mpz_init(&(var)); \
(flag) = TRUE; \
mpz_powm(&(var), &(base), &(exp), (mod)); \
}
#endif /* _MP_DEFS_H */
+869
View File
@@ -0,0 +1,869 @@
/* FreeS/WAN NAT-Traversal
* Copyright (C) 2002-2005 Mathieu Lafon - Arkoon Network Security
*
* 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: nat_traversal.c,v 1.8 2005/01/06 22:36:58 as Exp $
*/
#ifdef NAT_TRAVERSAL
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <syslog.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <signal.h> /* used only if MSG_NOSIGNAL not defined */
#include <sys/queue.h>
#include <freeswan.h>
#include <freeswan/ipsec_policy.h>
#include <pfkeyv2.h>
#include <pfkey.h>
#include "constants.h"
#include "defs.h"
#include "log.h"
#include "server.h"
#include "state.h"
#include "connections.h"
#include "packet.h"
#include "demux.h"
#include "kernel.h"
#include "whack.h"
#include "timer.h"
#include "cookie.h"
#include "sha1.h"
#include "md5.h"
#include "crypto.h"
#include "vendor.h"
#include "ike_alg.h"
#include "nat_traversal.h"
/* #define FORCE_NAT_TRAVERSAL */
#define NAT_D_DEBUG
#define NAT_T_SUPPORT_LAST_DRAFTS
#ifndef SOL_UDP
#define SOL_UDP 17
#endif
#ifndef UDP_ESPINUDP
#define UDP_ESPINUDP 100
#endif
#define DEFAULT_KEEP_ALIVE_PERIOD 20
#ifdef _IKE_ALG_H
/* Alg patch: hash_digest_len -> hash_digest_size */
#define hash_digest_len hash_digest_size
#endif
bool nat_traversal_enabled = FALSE;
bool nat_traversal_support_non_ike = FALSE;
bool nat_traversal_support_port_floating = FALSE;
static unsigned int _kap = 0;
static unsigned int _ka_evt = 0;
static bool _force_ka = 0;
static const char *natt_version = "0.6c";
void init_nat_traversal (bool activate, unsigned int keep_alive_period,
bool fka, bool spf)
{
nat_traversal_enabled = activate;
nat_traversal_support_non_ike = activate;
#ifdef NAT_T_SUPPORT_LAST_DRAFTS
nat_traversal_support_port_floating = activate ? spf : FALSE;
#endif
_force_ka = fka;
_kap = keep_alive_period ? keep_alive_period : DEFAULT_KEEP_ALIVE_PERIOD;
plog(" including NAT-Traversal patch (Version %s)%s%s%s"
, natt_version, activate ? "" : " [disabled]"
, activate & fka ? " [Force KeepAlive]" : ""
, activate & !spf ? " [Port Floating disabled]" : "");
}
static void disable_nat_traversal (int type)
{
if (type == ESPINUDP_WITH_NON_IKE)
nat_traversal_support_non_ike = FALSE;
else
nat_traversal_support_port_floating = FALSE;
if (!nat_traversal_support_non_ike &&
!nat_traversal_support_port_floating)
nat_traversal_enabled = FALSE;
}
static void _natd_hash(const struct hash_desc *hasher, char *hash,
u_int8_t *icookie, u_int8_t *rcookie,
const ip_address *ip, u_int16_t port)
{
union hash_ctx ctx;
if (is_zero_cookie(icookie))
DBG_log("_natd_hash: Warning, icookie is zero !!");
if (is_zero_cookie(rcookie))
DBG_log("_natd_hash: Warning, rcookie is zero !!");
/**
* draft-ietf-ipsec-nat-t-ike-01.txt
*
* HASH = HASH(CKY-I | CKY-R | IP | Port)
*
* All values in network order
*/
hasher->hash_init(&ctx);
hasher->hash_update(&ctx, icookie, COOKIE_SIZE);
hasher->hash_update(&ctx, rcookie, COOKIE_SIZE);
switch (addrtypeof(ip)) {
case AF_INET:
hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr
, sizeof(ip->u.v4.sin_addr.s_addr));
break;
case AF_INET6:
hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr
, sizeof(ip->u.v6.sin6_addr.s6_addr));
break;
}
hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t));
hasher->hash_final(hash, &ctx);
#ifdef NAT_D_DEBUG
DBG(DBG_NATT,
DBG_log("_natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len);
DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE);
DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE);
switch (addrtypeof(ip)) {
case AF_INET:
DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr
, sizeof(ip->u.v4.sin_addr.s_addr));
break;
}
DBG_log("_natd_hash: port=%d", port);
DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len);
);
#endif
}
/* Add NAT-Traversal VIDs (supported ones)
* used when we are Initiator
*/
bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs)
{
bool r = TRUE;
if (nat_traversal_support_port_floating)
{
u_int8_t last_np = nat_traversal_support_non_ike ?
ISAKMP_NEXT_VID : np;
if (r)
r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_RFC);
if (r)
r = out_vendorid(ISAKMP_NEXT_VID, outs, VID_NATT_IETF_03);
if (r)
r = out_vendorid(last_np, outs, VID_NATT_IETF_02);
}
if (nat_traversal_support_non_ike)
{
if (r)
r = out_vendorid(np, outs, VID_NATT_IETF_00);
}
return r;
}
u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid)
{
switch (nat_t_vid)
{
case VID_NATT_IETF_00:
return LELEM(NAT_TRAVERSAL_IETF_00_01);
case VID_NATT_IETF_02:
case VID_NATT_IETF_02_N:
case VID_NATT_IETF_03:
return LELEM(NAT_TRAVERSAL_IETF_02_03);
case VID_NATT_RFC:
return LELEM(NAT_TRAVERSAL_RFC);
}
return 0;
}
void nat_traversal_natd_lookup(struct msg_digest *md)
{
char hash[MAX_DIGEST_LEN];
struct payload_digest *p;
struct state *st = md->st;
int i;
if (!st || !md->iface || !st->st_oakley.hasher)
{
loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
, __FILE__, __LINE__);
return;
}
/** Count NAT-D **/
for (p = md->chain[ISAKMP_NEXT_NATD_RFC], i=0; p != NULL; p = p->next, i++);
/*
* We need at least 2 NAT-D (1 for us, many for peer)
*/
if (i < 2)
{
loglog(RC_LOG_SERIOUS,
"NAT-Traversal: Only %d NAT-D - Aborting NAT-Traversal negociation", i);
st->nat_traversal = 0;
return;
}
/*
* First one with my IP & port
*/
p = md->chain[ISAKMP_NEXT_NATD_RFC];
_natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie,
&(md->iface->addr), ntohs(st->st_connection->spd.this.host_port));
if (!(pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len &&
memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len) == 0))
{
#ifdef NAT_D_DEBUG
DBG(DBG_NATT,
DBG_log("NAT_TRAVERSAL_NAT_BHND_ME");
DBG_dump("expected NAT-D:", hash
, st->st_oakley.hasher->hash_digest_len);
DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
)
#endif
st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
}
/*
* The others with sender IP & port
*/
_natd_hash(st->st_oakley.hasher, hash, st->st_icookie, st->st_rcookie,
&(md->sender), ntohs(md->sender_port));
for (p = p->next, i=0 ; p != NULL; p = p->next)
{
if (pbs_left(&p->pbs) == st->st_oakley.hasher->hash_digest_len &&
memcmp(p->pbs.cur, hash, st->st_oakley.hasher->hash_digest_len) == 0)
{
i++;
}
}
if (!i)
{
#ifdef NAT_D_DEBUG
DBG(DBG_NATT,
DBG_log("NAT_TRAVERSAL_NAT_BHND_PEER");
DBG_dump("expected NAT-D:", hash
, st->st_oakley.hasher->hash_digest_len);
p = md->chain[ISAKMP_NEXT_NATD_RFC];
for (p = p->next, i=0 ; p != NULL; p = p->next)
{
DBG_dump("received NAT-D:", p->pbs.cur, pbs_left(&p->pbs));
}
)
#endif
st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
}
#ifdef FORCE_NAT_TRAVERSAL
st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_PEER);
st->nat_traversal |= LELEM(NAT_TRAVERSAL_NAT_BHND_ME);
#endif
}
bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs,
struct msg_digest *md)
{
char hash[MAX_DIGEST_LEN];
struct state *st = md->st;
if (!st || !st->st_oakley.hasher)
{
loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
, __FILE__, __LINE__);
return FALSE;
}
DBG(DBG_EMITTING,
DBG_log("sending NATD payloads")
)
/*
* First one with sender IP & port
*/
_natd_hash(st->st_oakley.hasher, hash, st->st_icookie,
is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie,
&(md->sender),
#ifdef FORCE_NAT_TRAVERSAL
0
#else
ntohs(md->sender_port)
#endif
);
if (!out_generic_raw((st->nat_traversal & NAT_T_WITH_RFC_VALUES
? ISAKMP_NEXT_NATD_RFC : ISAKMP_NEXT_NATD_DRAFTS), &isakmp_nat_d, outs,
hash, st->st_oakley.hasher->hash_digest_len, "NAT-D"))
{
return FALSE;
}
/*
* Second one with my IP & port
*/
_natd_hash(st->st_oakley.hasher, hash, st->st_icookie,
is_zero_cookie(st->st_rcookie) ? md->hdr.isa_rcookie : st->st_rcookie,
&(md->iface->addr),
#ifdef FORCE_NAT_TRAVERSAL
0
#else
ntohs(st->st_connection->spd.this.host_port)
#endif
);
return (out_generic_raw(np, &isakmp_nat_d, outs,
hash, st->st_oakley.hasher->hash_digest_len, "NAT-D"));
}
/*
* nat_traversal_natoa_lookup()
*
* Look for NAT-OA in message
*/
void nat_traversal_natoa_lookup(struct msg_digest *md)
{
struct payload_digest *p;
struct state *st = md->st;
int i;
ip_address ip;
if (!st || !md->iface)
{
loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
, __FILE__, __LINE__);
return;
}
/* Initialize NAT-OA */
anyaddr(AF_INET, &st->nat_oa);
/* Count NAT-OA **/
for (p = md->chain[ISAKMP_NEXT_NATOA_RFC], i=0; p != NULL; p = p->next, i++);
DBG(DBG_NATT,
DBG_log("NAT-Traversal: received %d NAT-OA.", i)
)
if (i == 0)
return;
if (!(st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER)))
{
loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. "
"ignored because peer is not NATed", i);
return;
}
if (i > 1)
{
loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %d NAT-OA. "
"using first, ignoring others", i);
}
/* Take first */
p = md->chain[ISAKMP_NEXT_NATOA_RFC];
DBG(DBG_PARSING,
DBG_dump("NAT-OA:", p->pbs.start, pbs_room(&p->pbs));
);
switch (p->payload.nat_oa.isanoa_idtype)
{
case ID_IPV4_ADDR:
if (pbs_left(&p->pbs) == sizeof(struct in_addr))
{
initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET, &ip);
}
else
{
loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv4 NAT-OA "
"with invalid IP size (%d)", (int)pbs_left(&p->pbs));
return;
}
break;
case ID_IPV6_ADDR:
if (pbs_left(&p->pbs) == sizeof(struct in6_addr))
{
initaddr(p->pbs.cur, pbs_left(&p->pbs), AF_INET6, &ip);
}
else
{
loglog(RC_LOG_SERIOUS, "NAT-Traversal: received IPv6 NAT-OA "
"with invalid IP size (%d)", (int)pbs_left(&p->pbs));
return;
}
break;
default:
loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
"invalid ID Type (%d) in NAT-OA - ignored",
p->payload.nat_oa.isanoa_idtype);
return;
}
DBG(DBG_NATT,
{
char ip_t[ADDRTOT_BUF];
addrtot(&ip, 0, ip_t, sizeof(ip_t));
DBG_log("received NAT-OA: %s", ip_t);
}
)
if (isanyaddr(&ip))
loglog(RC_LOG_SERIOUS, "NAT-Traversal: received %%any NAT-OA...");
else
st->nat_oa = ip;
}
bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs,
struct state *st)
{
struct isakmp_nat_oa natoa;
pb_stream pbs;
unsigned char ip_val[sizeof(struct in6_addr)];
size_t ip_len = 0;
ip_address *ip;
if ((!st) || (!st->st_connection))
{
loglog(RC_LOG_SERIOUS, "NAT-Traversal: assert failed %s:%d"
, __FILE__, __LINE__);
return FALSE;
}
ip = &(st->st_connection->spd.this.host_addr);
memset(&natoa, 0, sizeof(natoa));
natoa.isanoa_np = np;
switch (addrtypeof(ip))
{
case AF_INET:
ip_len = sizeof(ip->u.v4.sin_addr.s_addr);
memcpy(ip_val, &ip->u.v4.sin_addr.s_addr, ip_len);
natoa.isanoa_idtype = ID_IPV4_ADDR;
break;
case AF_INET6:
ip_len = sizeof(ip->u.v6.sin6_addr.s6_addr);
memcpy(ip_val, &ip->u.v6.sin6_addr.s6_addr, ip_len);
natoa.isanoa_idtype = ID_IPV6_ADDR;
break;
default:
loglog(RC_LOG_SERIOUS, "NAT-Traversal: "
"invalid addrtypeof()=%d", addrtypeof(ip));
return FALSE;
}
if (!out_struct(&natoa, &isakmp_nat_oa, outs, &pbs))
return FALSE;
if (!out_raw(ip_val, ip_len, &pbs, "NAT-OA"))
return FALSE;
DBG(DBG_NATT,
DBG_dump("NAT-OA (S):", ip_val, ip_len)
)
close_output_pbs(&pbs);
return TRUE;
}
void nat_traversal_show_result (u_int32_t nt, u_int16_t sport)
{
const char *mth = NULL, *rslt = NULL;
switch (nt & NAT_TRAVERSAL_METHOD)
{
case LELEM(NAT_TRAVERSAL_IETF_00_01):
mth = natt_type_bitnames[0];
break;
case LELEM(NAT_TRAVERSAL_IETF_02_03):
mth = natt_type_bitnames[1];
break;
case LELEM(NAT_TRAVERSAL_RFC):
mth = natt_type_bitnames[2];
break;
}
switch (nt & NAT_T_DETECTED)
{
case 0:
rslt = "no NAT detected";
break;
case LELEM(NAT_TRAVERSAL_NAT_BHND_ME):
rslt = "i am NATed";
break;
case LELEM(NAT_TRAVERSAL_NAT_BHND_PEER):
rslt = "peer is NATed";
break;
case LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER):
rslt = "both are NATed";
break;
}
loglog(RC_LOG_SERIOUS,
"NAT-Traversal: Result using %s: %s",
mth ? mth : "unknown method",
rslt ? rslt : "unknown result"
);
if ((nt & LELEM(NAT_TRAVERSAL_NAT_BHND_PEER))
&& (sport == IKE_UDP_PORT)
&& ((nt & NAT_T_WITH_PORT_FLOATING)==0))
{
loglog(RC_LOG_SERIOUS,
"Warning: peer is NATed but source port is still udp/%d. "
"Ipsec-passthrough NAT device suspected -- NAT-T may not work.",
IKE_UDP_PORT
);
}
}
int nat_traversal_espinudp_socket (int sk, u_int32_t type)
{
int r = setsockopt(sk, SOL_UDP, UDP_ESPINUDP, &type, sizeof(type));
if (r < 0 && errno == ENOPROTOOPT)
{
loglog(RC_LOG_SERIOUS,
"NAT-Traversal: ESPINUDP(%d) not supported by kernel -- "
"NAT-T disabled", type);
disable_nat_traversal(type);
}
return r;
}
void nat_traversal_new_ka_event (void)
{
if (_ka_evt)
return; /* event already scheduled */
event_schedule(EVENT_NAT_T_KEEPALIVE, _kap, NULL);
_ka_evt = 1;
}
static void nat_traversal_send_ka (struct state *st)
{
static unsigned char ka_payload = 0xff;
chunk_t sav;
DBG(DBG_NATT,
DBG_log("ka_event: send NAT-KA to %s:%d",
ip_str(&st->st_connection->spd.that.host_addr),
st->st_connection->spd.that.host_port);
)
/* save state chunk */
setchunk(sav, st->st_tpacket.ptr, st->st_tpacket.len);
/* send keep alive */
setchunk(st->st_tpacket, &ka_payload, 1);
_send_packet(st, "NAT-T Keep Alive", FALSE);
/* restore state chunk */
setchunk(st->st_tpacket, sav.ptr, sav.len);
}
/**
* Find ISAKMP States with NAT-T and send keep-alive
*/
static void nat_traversal_ka_event_state (struct state *st, void *data)
{
unsigned int *_kap_st = (unsigned int *)data;
const struct connection *c = st->st_connection;
if (!c)
return;
if ((st->st_state == STATE_MAIN_R3 || st->st_state == STATE_MAIN_I4)
&& (st->nat_traversal & NAT_T_DETECTED)
&& ((st->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka))
{
/*
* - ISAKMP established
* - NAT-Traversal detected
* - NAT-KeepAlive needed (we are NATed)
*/
if (c->newest_isakmp_sa != st->st_serialno)
{
/*
* if newest is also valid, ignore this one, we will only use
* newest.
*/
struct state *st_newest;
st_newest = state_with_serialno(c->newest_isakmp_sa);
if (st_newest
&& (st_newest->st_state == STATE_MAIN_R3 || st_newest->st_state == STATE_MAIN_I4)
&& (st_newest->nat_traversal & NAT_T_DETECTED)
&& ((st_newest->nat_traversal & LELEM(NAT_TRAVERSAL_NAT_BHND_ME)) || _force_ka))
{
return;
}
}
set_cur_state(st);
nat_traversal_send_ka(st);
reset_cur_state();
(*_kap_st)++;
}
}
void nat_traversal_ka_event (void)
{
unsigned int _kap_st = 0;
_ka_evt = 0; /* ready to be reschedule */
for_each_state((void *)nat_traversal_ka_event_state, &_kap_st);
/* if there are still states who needs Keep-Alive, schedule new event */
if (_kap_st)
nat_traversal_new_ka_event();
}
struct _new_mapp_nfo {
ip_address addr;
u_int16_t sport, dport;
};
static void nat_traversal_find_new_mapp_state (struct state *st, void *data)
{
struct connection *c = st->st_connection;
struct _new_mapp_nfo *nfo = (struct _new_mapp_nfo *)data;
if (c != NULL
&& sameaddr(&c->spd.that.host_addr, &(nfo->addr))
&& c->spd.that.host_port == nfo->sport)
{
/* change host port */
c->spd.that.host_port = nfo->dport;
if (IS_IPSEC_SA_ESTABLISHED(st->st_state)
|| IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state))
{
if (!update_ipsec_sa(st))
{
/*
* If ipsec update failed, restore old port or we'll
* not be able to update anymore.
*/
c->spd.that.host_port = nfo->sport;
}
}
}
}
static int nat_traversal_new_mapping(const ip_address *src, u_int16_t sport,
const ip_address *dst, u_int16_t dport)
{
char srca[ADDRTOT_BUF], dsta[ADDRTOT_BUF];
struct _new_mapp_nfo nfo;
addrtot(src, 0, srca, ADDRTOT_BUF);
addrtot(dst, 0, dsta, ADDRTOT_BUF);
if (!sameaddr(src, dst))
{
loglog(RC_LOG_SERIOUS, "nat_traversal_new_mapping: "
"address change currently not supported [%s:%d,%s:%d]",
srca, sport, dsta, dport);
return -1;
}
if (sport == dport)
{
/* no change */
return 0;
}
DBG_log("NAT-T: new mapping %s:%d/%d)", srca, sport, dport);
nfo.addr = *src;
nfo.sport = sport;
nfo.dport = dport;
for_each_state((void *)nat_traversal_find_new_mapp_state, &nfo);
return 0;
}
void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st)
{
struct connection *c = st ? st->st_connection : NULL;
struct iface *i = NULL;
if ((st == NULL) || (c == NULL))
return;
if (md)
{
/*
* If source port has changed, update (including other states and
* established kernel SA)
*/
if (c->spd.that.host_port != md->sender_port)
{
nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port,
&c->spd.that.host_addr, md->sender_port);
}
/*
* If interface type has changed, update local port (500/4500)
*/
if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !md->iface->ike_float)
|| (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && md->iface->ike_float))
{
c->spd.this.host_port = (md->iface->ike_float)
? NAT_T_IKE_FLOAT_PORT : pluto_port;
DBG(DBG_NATT,
DBG_log("NAT-T: updating local port to %d", c->spd.this.host_port);
);
}
}
/*
* If we're initiator and NAT-T (with port floating) is detected, we
* need to change port (MAIN_I3 or QUICK_I1)
*/
if ((st->st_state == STATE_MAIN_I3 || st->st_state == STATE_QUICK_I1)
&& (st->nat_traversal & NAT_T_WITH_PORT_FLOATING)
&& (st->nat_traversal & NAT_T_DETECTED)
&& (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT))
{
DBG(DBG_NATT,
DBG_log("NAT-T: floating to port %d", NAT_T_IKE_FLOAT_PORT);
)
c->spd.this.host_port = NAT_T_IKE_FLOAT_PORT;
c->spd.that.host_port = NAT_T_IKE_FLOAT_PORT;
/*
* Also update pending connections or they will be deleted if uniqueids
* option is set.
*/
update_pending(st, st);
}
/*
* Find valid interface according to local port (500/4500)
*/
if ((c->spd.this.host_port == NAT_T_IKE_FLOAT_PORT && !c->interface->ike_float)
|| (c->spd.this.host_port != NAT_T_IKE_FLOAT_PORT && c->interface->ike_float))
{
for (i = interfaces; i != NULL; i = i->next)
{
if (sameaddr(&c->interface->addr, &i->addr)
&& i->ike_float != c->interface->ike_float)
{
DBG(DBG_NATT,
DBG_log("NAT-T: using interface %s:%d", i->rname,
i->ike_float ? NAT_T_IKE_FLOAT_PORT : pluto_port);
)
c->interface = i;
break;
}
}
}
}
struct _new_klips_mapp_nfo {
struct sadb_sa *sa;
ip_address src, dst;
u_int16_t sport, dport;
};
static void nat_t_new_klips_mapp (struct state *st, void *data)
{
struct connection *c = st->st_connection;
struct _new_klips_mapp_nfo *nfo = (struct _new_klips_mapp_nfo *)data;
if (c != NULL && st->st_esp.present
&& sameaddr(&c->spd.that.host_addr, &(nfo->src))
&& st->st_esp.our_spi == nfo->sa->sadb_sa_spi)
{
nat_traversal_new_mapping(&c->spd.that.host_addr, c->spd.that.host_port,
&(nfo->dst), nfo->dport);
}
}
void process_pfkey_nat_t_new_mapping(
struct sadb_msg *msg __attribute__ ((unused)),
struct sadb_ext *extensions[SADB_EXT_MAX + 1])
{
struct _new_klips_mapp_nfo nfo;
struct sadb_address *srcx = (void *) extensions[SADB_EXT_ADDRESS_SRC];
struct sadb_address *dstx = (void *) extensions[SADB_EXT_ADDRESS_DST];
struct sockaddr *srca, *dsta;
err_t ugh = NULL;
nfo.sa = (void *) extensions[SADB_EXT_SA];
if (!nfo.sa || !srcx || !dstx)
{
plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: "
"got NULL params");
return;
}
srca = ((struct sockaddr *)(void *)&srcx[1]);
dsta = ((struct sockaddr *)(void *)&dstx[1]);
if (srca->sa_family != AF_INET || dsta->sa_family != AF_INET)
{
ugh = "only AF_INET supported";
}
else
{
char text_said[SATOT_BUF];
char _srca[ADDRTOT_BUF], _dsta[ADDRTOT_BUF];
ip_said said;
initaddr((const void *) &((const struct sockaddr_in *)srca)->sin_addr,
sizeof(((const struct sockaddr_in *)srca)->sin_addr),
srca->sa_family, &(nfo.src));
nfo.sport = ntohs(((const struct sockaddr_in *)srca)->sin_port);
initaddr((const void *) &((const struct sockaddr_in *)dsta)->sin_addr,
sizeof(((const struct sockaddr_in *)dsta)->sin_addr),
dsta->sa_family, &(nfo.dst));
nfo.dport = ntohs(((const struct sockaddr_in *)dsta)->sin_port);
DBG(DBG_NATT,
initsaid(&nfo.src, nfo.sa->sadb_sa_spi, SA_ESP, &said);
satot(&said, 0, text_said, SATOT_BUF);
addrtot(&nfo.src, 0, _srca, ADDRTOT_BUF);
addrtot(&nfo.dst, 0, _dsta, ADDRTOT_BUF);
DBG_log("new klips mapping %s %s:%d %s:%d",
text_said, _srca, nfo.sport, _dsta, nfo.dport);
)
for_each_state((void *)nat_t_new_klips_mapp, &nfo);
}
if (ugh != NULL)
plog("SADB_X_NAT_T_NEW_MAPPING message from KLIPS malformed: %s", ugh);
}
#endif
+154
View File
@@ -0,0 +1,154 @@
/* FreeS/WAN NAT-Traversal
* Copyright (C) 2002-2003 Mathieu Lafon - Arkoon Network Security
*
* 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: nat_traversal.h,v 1.4 2004/07/27 21:11:30 as Exp $
*/
#ifndef _NAT_TRAVERSAL_H
#define _NAT_TRAVERSAL_H
#include "packet.h"
#define NAT_TRAVERSAL_IETF_00_01 1
#define NAT_TRAVERSAL_IETF_02_03 2
#define NAT_TRAVERSAL_RFC 3
#define NAT_TRAVERSAL_NAT_BHND_ME 30
#define NAT_TRAVERSAL_NAT_BHND_PEER 31
#define NAT_TRAVERSAL_METHOD (0xffffffff - LELEM(30) - LELEM(31))
/**
* NAT-Traversal methods which need NAT-D
*/
#define NAT_T_WITH_NATD \
( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
LELEM(NAT_TRAVERSAL_RFC) )
/**
* NAT-Traversal methods which need NAT-OA
*/
#define NAT_T_WITH_NATOA \
( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
LELEM(NAT_TRAVERSAL_RFC) )
/**
* NAT-Traversal methods which use NAT-KeepAlive
*/
#define NAT_T_WITH_KA \
( LELEM(NAT_TRAVERSAL_IETF_00_01) | LELEM(NAT_TRAVERSAL_IETF_02_03) | \
LELEM(NAT_TRAVERSAL_RFC) )
/**
* NAT-Traversal methods which use floating port
*/
#define NAT_T_WITH_PORT_FLOATING \
( LELEM(NAT_TRAVERSAL_IETF_02_03) | LELEM(NAT_TRAVERSAL_RFC) )
/**
* NAT-Traversal methods which use officials values (RFC)
*/
#define NAT_T_WITH_RFC_VALUES \
( LELEM(NAT_TRAVERSAL_RFC) )
/**
* NAT-Traversal detected
*/
#define NAT_T_DETECTED \
( LELEM(NAT_TRAVERSAL_NAT_BHND_ME) | LELEM(NAT_TRAVERSAL_NAT_BHND_PEER) )
/**
* NAT-T Port Floating
*/
#define NAT_T_IKE_FLOAT_PORT 4500
void init_nat_traversal (bool activate, unsigned int keep_alive_period,
bool fka, bool spf);
extern bool nat_traversal_enabled;
extern bool nat_traversal_support_non_ike;
extern bool nat_traversal_support_port_floating;
/**
* NAT-D
*/
void nat_traversal_natd_lookup(struct msg_digest *md);
#ifndef PB_STREAM_UNDEFINED
bool nat_traversal_add_natd(u_int8_t np, pb_stream *outs,
struct msg_digest *md);
#endif
/**
* NAT-OA
*/
void nat_traversal_natoa_lookup(struct msg_digest *md);
#ifndef PB_STREAM_UNDEFINED
bool nat_traversal_add_natoa(u_int8_t np, pb_stream *outs,
struct state *st);
#endif
/**
* NAT-keep_alive
*/
void nat_traversal_new_ka_event (void);
void nat_traversal_ka_event (void);
void nat_traversal_show_result (u_int32_t nt, u_int16_t sport);
int nat_traversal_espinudp_socket (int sk, u_int32_t type);
/**
* Vendor ID
*/
#ifndef PB_STREAM_UNDEFINED
bool nat_traversal_add_vid(u_int8_t np, pb_stream *outs);
#endif
u_int32_t nat_traversal_vid_to_method(unsigned short nat_t_vid);
void nat_traversal_change_port_lookup(struct msg_digest *md, struct state *st);
/**
* New NAT mapping
*/
#ifdef __PFKEY_V2_H
void process_pfkey_nat_t_new_mapping(
struct sadb_msg *,
struct sadb_ext *[SADB_EXT_MAX + 1]);
#endif
/**
* IKE port floating
*/
bool
nat_traversal_port_float(struct state *st, struct msg_digest *md, bool in);
/**
* Encapsulation mode macro (see demux.c)
*/
#define NAT_T_ENCAPSULATION_MODE(st,nat_t_policy) ( \
((st)->nat_traversal & NAT_T_DETECTED) \
? ( ((nat_t_policy) & POLICY_TUNNEL) \
? ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \
? (ENCAPSULATION_MODE_UDP_TUNNEL_RFC) \
: (ENCAPSULATION_MODE_UDP_TUNNEL_DRAFTS) \
) \
: ( ((st)->nat_traversal & NAT_T_WITH_RFC_VALUES) \
? (ENCAPSULATION_MODE_UDP_TRANSPORT_RFC) \
: (ENCAPSULATION_MODE_UDP_TRANSPORT_DRAFTS) \
) \
) \
: ( ((st)->st_policy & POLICY_TUNNEL) \
? (ENCAPSULATION_MODE_TUNNEL) \
: (ENCAPSULATION_MODE_TRANSPORT) \
) \
)
#endif /* _NAT_TRAVERSAL_H */
+1568
View File
File diff suppressed because it is too large Load Diff
+85
View File
@@ -0,0 +1,85 @@
/* Support of the Online Certificate Status Protocol (OCSP) Support
* Copyright (C) 2003 Christoph Gysin, Simon Zwahlen
* Zuercher Hochschule Winterthur
*
* 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.
*
*/
#include "constants.h"
/* constants */
#define OCSP_BASIC_RESPONSE_VERSION 1
#define OCSP_DEFAULT_VALID_TIME 120 /* validity of one-time response in seconds */
#define OCSP_WARNING_INTERVAL 2 /* days */
/* OCSP response status */
typedef enum {
STATUS_SUCCESSFUL = 0,
STATUS_MALFORMEDREQUEST = 1,
STATUS_INTERNALERROR = 2,
STATUS_TRYLATER = 3,
STATUS_SIGREQUIRED = 5,
STATUS_UNAUTHORIZED= 6
} response_status;
/* OCSP access structures */
typedef struct ocsp_certinfo ocsp_certinfo_t;
struct ocsp_certinfo {
ocsp_certinfo_t *next;
int trials;
chunk_t serialNumber;
cert_status_t status;
bool once;
crl_reason_t revocationReason;
time_t revocationTime;
time_t thisUpdate;
time_t nextUpdate;
};
typedef struct ocsp_location ocsp_location_t;
struct ocsp_location {
ocsp_location_t *next;
chunk_t issuer;
chunk_t authNameID;
chunk_t authKeyID;
chunk_t authKeySerialNumber;
chunk_t uri;
chunk_t nonce;
ocsp_certinfo_t *certinfo;
};
extern ocsp_location_t* get_ocsp_location(const ocsp_location_t *loc
, ocsp_location_t *chain);
extern ocsp_location_t* add_ocsp_location(const ocsp_location_t *loc
, ocsp_location_t **chain);
extern void add_certinfo(ocsp_location_t *loc, ocsp_certinfo_t *info
, ocsp_location_t **chain, bool request);
extern void check_ocsp(void);
extern cert_status_t verify_by_ocsp(const x509cert_t *cert, time_t *until
, time_t *revocationTime, crl_reason_t *revocationReason);
extern bool ocsp_set_request_cert(char* path);
extern void ocsp_set_default_uri(char* uri);
extern void ocsp_cache_add_cert(const x509cert_t* cert);
extern chunk_t build_ocsp_request(ocsp_location_t* location);
extern void parse_ocsp(ocsp_location_t* location, chunk_t blob);
extern void list_ocsp_locations(ocsp_location_t *location, bool requests
, bool utc, bool strict);
extern void list_ocsp_cache(bool utc, bool strict);
extern void free_ocsp_locations(ocsp_location_t **chain);
extern void free_ocsp_cache(void);
extern void free_ocsp(void);
extern void ocsp_purge_cache(void);
+197
View File
@@ -0,0 +1,197 @@
/* List of some useful object identifiers (OIDs)
* Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* This file has been automatically generated by the script oid.pl
* Do not edit manually!
*/
#include <stdlib.h>
#include "oid.h"
const oid_t oid_names[] = {
{0x02, 7, 1, "ITU-T Administration" }, /* 0 */
{ 0x82, 0, 1, "" }, /* 1 */
{ 0x06, 0, 1, "Germany ITU-T member" }, /* 2 */
{ 0x01, 0, 1, "Deutsche Telekom AG" }, /* 3 */
{ 0x0A, 0, 1, "" }, /* 4 */
{ 0x07, 0, 1, "" }, /* 5 */
{ 0x14, 0, 0, "ND" }, /* 6 */
{0x09, 18, 1, "data" }, /* 7 */
{ 0x92, 0, 1, "" }, /* 8 */
{ 0x26, 0, 1, "" }, /* 9 */
{ 0x89, 0, 1, "" }, /* 10 */
{ 0x93, 0, 1, "" }, /* 11 */
{ 0xF2, 0, 1, "" }, /* 12 */
{ 0x2C, 0, 1, "" }, /* 13 */
{ 0x64, 0, 1, "pilot" }, /* 14 */
{ 0x01, 0, 1, "pilotAttributeType" }, /* 15 */
{ 0x01, 17, 0, "UID" }, /* 16 */
{ 0x19, 0, 0, "DC" }, /* 17 */
{0x55, 51, 1, "X.500" }, /* 18 */
{ 0x04, 36, 1, "X.509" }, /* 19 */
{ 0x03, 21, 0, "CN" }, /* 20 */
{ 0x04, 22, 0, "S" }, /* 21 */
{ 0x05, 23, 0, "SN" }, /* 22 */
{ 0x06, 24, 0, "C" }, /* 23 */
{ 0x07, 25, 0, "L" }, /* 24 */
{ 0x08, 26, 0, "ST" }, /* 25 */
{ 0x0A, 27, 0, "O" }, /* 26 */
{ 0x0B, 28, 0, "OU" }, /* 27 */
{ 0x0C, 29, 0, "T" }, /* 28 */
{ 0x0D, 30, 0, "D" }, /* 29 */
{ 0x24, 31, 0, "userCertificate" }, /* 30 */
{ 0x29, 32, 0, "N" }, /* 31 */
{ 0x2A, 33, 0, "G" }, /* 32 */
{ 0x2B, 34, 0, "I" }, /* 33 */
{ 0x2D, 35, 0, "ID" }, /* 34 */
{ 0x48, 0, 0, "role" }, /* 35 */
{ 0x1D, 0, 1, "id-ce" }, /* 36 */
{ 0x09, 38, 0, "subjectDirectoryAttrs" }, /* 37 */
{ 0x0E, 39, 0, "subjectKeyIdentifier" }, /* 38 */
{ 0x0F, 40, 0, "keyUsage" }, /* 39 */
{ 0x10, 41, 0, "privateKeyUsagePeriod" }, /* 40 */
{ 0x11, 42, 0, "subjectAltName" }, /* 41 */
{ 0x12, 43, 0, "issuerAltName" }, /* 42 */
{ 0x13, 44, 0, "basicConstraints" }, /* 43 */
{ 0x15, 45, 0, "reasonCode" }, /* 44 */
{ 0x1F, 46, 0, "crlDistributionPoints" }, /* 45 */
{ 0x20, 47, 0, "certificatePolicies" }, /* 46 */
{ 0x23, 48, 0, "authorityKeyIdentifier" }, /* 47 */
{ 0x25, 49, 0, "extendedKeyUsage" }, /* 48 */
{ 0x37, 50, 0, "targetInformation" }, /* 49 */
{ 0x38, 0, 0, "noRevAvail" }, /* 50 */
{0x2A, 88, 1, "" }, /* 51 */
{ 0x86, 0, 1, "" }, /* 52 */
{ 0x48, 0, 1, "" }, /* 53 */
{ 0x86, 0, 1, "" }, /* 54 */
{ 0xF7, 0, 1, "" }, /* 55 */
{ 0x0D, 0, 1, "RSADSI" }, /* 56 */
{ 0x01, 83, 1, "PKCS" }, /* 57 */
{ 0x01, 66, 1, "PKCS-1" }, /* 58 */
{ 0x01, 60, 0, "rsaEncryption" }, /* 59 */
{ 0x02, 61, 0, "md2WithRSAEncryption" }, /* 60 */
{ 0x04, 62, 0, "md5WithRSAEncryption" }, /* 61 */
{ 0x05, 63, 0, "sha-1WithRSAEncryption" }, /* 62 */
{ 0x0B, 64, 0, "sha256WithRSAEncryption"}, /* 63 */
{ 0x0C, 65, 0, "sha384WithRSAEncryption"}, /* 64 */
{ 0x0D, 0, 0, "sha512WithRSAEncryption"}, /* 65 */
{ 0x07, 73, 1, "PKCS-7" }, /* 66 */
{ 0x01, 68, 0, "data" }, /* 67 */
{ 0x02, 69, 0, "signedData" }, /* 68 */
{ 0x03, 70, 0, "envelopedData" }, /* 69 */
{ 0x04, 71, 0, "signedAndEnvelopedData" }, /* 70 */
{ 0x05, 72, 0, "digestedData" }, /* 71 */
{ 0x06, 0, 0, "encryptedData" }, /* 72 */
{ 0x09, 0, 1, "PKCS-9" }, /* 73 */
{ 0x01, 75, 0, "E" }, /* 74 */
{ 0x02, 76, 0, "unstructuredName" }, /* 75 */
{ 0x03, 77, 0, "contentType" }, /* 76 */
{ 0x04, 78, 0, "messageDigest" }, /* 77 */
{ 0x05, 79, 0, "signingTime" }, /* 78 */
{ 0x06, 80, 0, "counterSignature" }, /* 79 */
{ 0x07, 81, 0, "challengePassword" }, /* 80 */
{ 0x08, 82, 0, "unstructuredAddress" }, /* 81 */
{ 0x0E, 0, 0, "extensionRequest" }, /* 82 */
{ 0x02, 86, 1, "digestAlgorithm" }, /* 83 */
{ 0x02, 85, 0, "md2" }, /* 84 */
{ 0x05, 0, 0, "md5" }, /* 85 */
{ 0x03, 0, 1, "encryptionAlgorithm" }, /* 86 */
{ 0x07, 0, 0, "3des-ede-cbc" }, /* 87 */
{0x2B, 149, 1, "" }, /* 88 */
{ 0x06, 136, 1, "dod" }, /* 89 */
{ 0x01, 0, 1, "internet" }, /* 90 */
{ 0x04, 105, 1, "private" }, /* 91 */
{ 0x01, 0, 1, "enterprise" }, /* 92 */
{ 0x82, 98, 1, "" }, /* 93 */
{ 0x37, 0, 1, "Microsoft" }, /* 94 */
{ 0x0A, 0, 1, "" }, /* 95 */
{ 0x03, 0, 1, "" }, /* 96 */
{ 0x03, 0, 0, "msSGC" }, /* 97 */
{ 0x89, 0, 1, "" }, /* 98 */
{ 0x31, 0, 1, "" }, /* 99 */
{ 0x01, 0, 1, "" }, /* 100 */
{ 0x01, 0, 1, "" }, /* 101 */
{ 0x02, 0, 1, "" }, /* 102 */
{ 0x02, 104, 0, "" }, /* 103 */
{ 0x4B, 0, 0, "TCGID" }, /* 104 */
{ 0x05, 0, 1, "security" }, /* 105 */
{ 0x05, 0, 1, "mechanisms" }, /* 106 */
{ 0x07, 0, 1, "id-pkix" }, /* 107 */
{ 0x01, 110, 1, "id-pe" }, /* 108 */
{ 0x01, 0, 0, "authorityInfoAccess" }, /* 109 */
{ 0x03, 120, 1, "id-kp" }, /* 110 */
{ 0x01, 112, 0, "serverAuth" }, /* 111 */
{ 0x02, 113, 0, "clientAuth" }, /* 112 */
{ 0x03, 114, 0, "codeSigning" }, /* 113 */
{ 0x04, 115, 0, "emailProtection" }, /* 114 */
{ 0x05, 116, 0, "ipsecEndSystem" }, /* 115 */
{ 0x06, 117, 0, "ipsecTunnel" }, /* 116 */
{ 0x07, 118, 0, "ipsecUser" }, /* 117 */
{ 0x08, 119, 0, "timeStamping" }, /* 118 */
{ 0x09, 0, 0, "ocspSigning" }, /* 119 */
{ 0x08, 122, 1, "id-otherNames" }, /* 120 */
{ 0x05, 0, 0, "xmppAddr" }, /* 121 */
{ 0x0A, 127, 1, "id-aca" }, /* 122 */
{ 0x01, 124, 0, "authenticationInfo" }, /* 123 */
{ 0x02, 125, 0, "accessIdentity" }, /* 124 */
{ 0x03, 126, 0, "chargingIdentity" }, /* 125 */
{ 0x04, 0, 0, "group" }, /* 126 */
{ 0x30, 0, 1, "id-ad" }, /* 127 */
{ 0x01, 0, 1, "ocsp" }, /* 128 */
{ 0x01, 130, 0, "basic" }, /* 129 */
{ 0x02, 131, 0, "nonce" }, /* 130 */
{ 0x03, 132, 0, "crl" }, /* 131 */
{ 0x04, 133, 0, "response" }, /* 132 */
{ 0x05, 134, 0, "noCheck" }, /* 133 */
{ 0x06, 135, 0, "archiveCutoff" }, /* 134 */
{ 0x07, 0, 0, "serviceLocator" }, /* 135 */
{ 0x0E, 142, 1, "oiw" }, /* 136 */
{ 0x03, 0, 1, "secsig" }, /* 137 */
{ 0x02, 0, 1, "algorithms" }, /* 138 */
{ 0x07, 140, 0, "des-cbc" }, /* 139 */
{ 0x1A, 141, 0, "sha-1" }, /* 140 */
{ 0x1D, 0, 0, "sha-1WithRSASignature" }, /* 141 */
{ 0x24, 0, 1, "TeleTrusT" }, /* 142 */
{ 0x03, 0, 1, "algorithm" }, /* 143 */
{ 0x03, 0, 1, "signatureAlgorithm" }, /* 144 */
{ 0x01, 0, 1, "rsaSignature" }, /* 145 */
{ 0x02, 147, 0, "rsaSigWithripemd160" }, /* 146 */
{ 0x03, 148, 0, "rsaSigWithripemd128" }, /* 147 */
{ 0x04, 0, 0, "rsaSigWithripemd256" }, /* 148 */
{0x60, 0, 1, "" }, /* 149 */
{ 0x86, 0, 1, "" }, /* 150 */
{ 0x48, 0, 1, "" }, /* 151 */
{ 0x01, 0, 1, "organization" }, /* 152 */
{ 0x65, 160, 1, "gov" }, /* 153 */
{ 0x03, 0, 1, "csor" }, /* 154 */
{ 0x04, 0, 1, "nistalgorithm" }, /* 155 */
{ 0x02, 0, 1, "hashalgs" }, /* 156 */
{ 0x01, 158, 0, "id-SHA-256" }, /* 157 */
{ 0x02, 159, 0, "id-SHA-384" }, /* 158 */
{ 0x03, 0, 0, "id-SHA-512" }, /* 159 */
{ 0x86, 0, 1, "" }, /* 160 */
{ 0xf8, 0, 1, "" }, /* 161 */
{ 0x42, 174, 1, "netscape" }, /* 162 */
{ 0x01, 169, 1, "" }, /* 163 */
{ 0x01, 165, 0, "nsCertType" }, /* 164 */
{ 0x03, 166, 0, "nsRevocationUrl" }, /* 165 */
{ 0x04, 167, 0, "nsCaRevocationUrl" }, /* 166 */
{ 0x08, 168, 0, "nsCaPolicyUrl" }, /* 167 */
{ 0x0d, 0, 0, "nsComment" }, /* 168 */
{ 0x03, 172, 1, "directory" }, /* 169 */
{ 0x01, 0, 1, "" }, /* 170 */
{ 0x03, 0, 0, "employeeNumber" }, /* 171 */
{ 0x04, 0, 1, "policy" }, /* 172 */
{ 0x01, 0, 0, "nsSGC" }, /* 173 */
{ 0x45, 0, 1, "verisign" }, /* 174 */
{ 0x01, 0, 1, "pki" }, /* 175 */
{ 0x09, 0, 1, "attributes" }, /* 176 */
{ 0x02, 178, 0, "messageType" }, /* 177 */
{ 0x03, 179, 0, "pkiStatus" }, /* 178 */
{ 0x04, 180, 0, "failInfo" }, /* 179 */
{ 0x05, 181, 0, "senderNonce" }, /* 180 */
{ 0x06, 182, 0, "recipientNonce" }, /* 181 */
{ 0x07, 183, 0, "transID" }, /* 182 */
{ 0x08, 0, 0, "extensionReq" } /* 183 */
};
+75
View File
@@ -0,0 +1,75 @@
/* Object identifiers (OIDs) used by FreeS/WAN
* Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
*
* This file has been automatically generated by the script oid.pl
* Do not edit manually!
*/
typedef struct {
u_char octet;
u_int next;
u_int down;
const u_char *name;
} oid_t;
extern const oid_t oid_names[];
#define OID_UNKNOWN -1
#define OID_ROLE 35
#define OID_SUBJECT_KEY_ID 38
#define OID_SUBJECT_ALT_NAME 41
#define OID_BASIC_CONSTRAINTS 43
#define OID_CRL_REASON_CODE 44
#define OID_CRL_DISTRIBUTION_POINTS 45
#define OID_AUTHORITY_KEY_ID 47
#define OID_EXTENDED_KEY_USAGE 48
#define OID_TARGET_INFORMATION 49
#define OID_NO_REV_AVAIL 50
#define OID_RSA_ENCRYPTION 59
#define OID_MD2_WITH_RSA 60
#define OID_MD5_WITH_RSA 61
#define OID_SHA1_WITH_RSA 62
#define OID_SHA256_WITH_RSA 63
#define OID_SHA384_WITH_RSA 64
#define OID_SHA512_WITH_RSA 65
#define OID_PKCS7_DATA 67
#define OID_PKCS7_SIGNED_DATA 68
#define OID_PKCS7_ENVELOPED_DATA 69
#define OID_PKCS7_SIGNED_ENVELOPED_DATA 70
#define OID_PKCS7_DIGESTED_DATA 71
#define OID_PKCS7_ENCRYPTED_DATA 72
#define OID_PKCS9_EMAIL 74
#define OID_PKCS9_CONTENT_TYPE 76
#define OID_PKCS9_MESSAGE_DIGEST 77
#define OID_PKCS9_SIGNING_TIME 78
#define OID_MD2 84
#define OID_MD5 85
#define OID_3DES_EDE_CBC 87
#define OID_AUTHORITY_INFO_ACCESS 109
#define OID_OCSP_SIGNING 119
#define OID_XMPP_ADDR 121
#define OID_AUTHENTICATION_INFO 123
#define OID_ACCESS_IDENTITY 124
#define OID_CHARGING_IDENTITY 125
#define OID_GROUP 126
#define OID_OCSP 128
#define OID_BASIC 129
#define OID_NONCE 130
#define OID_CRL 131
#define OID_RESPONSE 132
#define OID_NO_CHECK 133
#define OID_ARCHIVE_CUTOFF 134
#define OID_SERVICE_LOCATOR 135
#define OID_DES_CBC 139
#define OID_SHA1 140
#define OID_SHA1_WITH_RSA_OIW 141
#define OID_NS_REVOCATION_URL 165
#define OID_NS_CA_REVOCATION_URL 166
#define OID_NS_CA_POLICY_URL 167
#define OID_NS_COMMENT 168
#define OID_PKI_MESSAGE_TYPE 177
#define OID_PKI_STATUS 178
#define OID_PKI_FAIL_INFO 179
#define OID_PKI_SENDER_NONCE 180
#define OID_PKI_RECIPIENT_NONCE 181
#define OID_PKI_TRANS_ID 182
+123
View File
@@ -0,0 +1,123 @@
#!/usr/bin/perl
# Generates oid.h and oid.c out of oid.txt
# Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur
#
# 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.
#
$copyright="Copyright (C) 2003-2004 Andreas Steffen, Zuercher Hochschule Winterthur";
$automatic="This file has been automatically generated by the script oid.pl";
$warning="Do not edit manually!";
print "oid.pl generating oid.h and oid.c\n";
# Generate oid.h
open(OID_H, ">oid.h")
or die "could not open 'oid.h': $!";
print OID_H "/* Object identifiers (OIDs) used by FreeS/WAN\n",
" * ", $copyright, "\n",
" * \n",
" * ", $automatic, "\n",
" * ", $warning, "\n",
" */\n\n",
"typedef struct {\n",
" u_char octet;\n",
" u_int next;\n",
" u_int down;\n",
" const u_char *name;\n",
"} oid_t;\n",
"\n",
"extern const oid_t oid_names[];\n",
"\n",
"#define OID_UNKNOWN -1\n";
# parse oid.txt
open(SRC, "<oid.txt")
or die "could not open 'oid.txt': $!";
$counter = 0;
$max_name = 0;
$max_order = 0;
while ($line = <SRC>)
{
$line =~ m/( *?)(0x\w{2})\s+(".*?")[ \t]*?([\w_]*?)\Z/;
@order[$counter] = length($1);
@octet[$counter] = $2;
@name[$counter] = $3;
if (length($1) > $max_order)
{
$max_order = length($1);
}
if (length($3) > $max_name)
{
$max_name = length($3);
}
if (length($4) > 0)
{
printf OID_H "#define %s%s%d\n", $4, "\t" x ((39-length($4))/8), $counter;
}
$counter++;
}
close SRC;
close OID_H;
# Generate oid.c
open(OID_C, ">oid.c")
or die "could not open 'oid.c': $!";
print OID_C "/* List of some useful object identifiers (OIDs)\n",
" * ", $copyright, "\n",
" * \n",
" * ", $automatic, "\n",
" * ", $warning, "\n",
" */\n",
"\n",
"#include <stdlib.h>\n",
"\n",
"#include \"oid.h\"\n",
"\n",
"const oid_t oid_names[] = {\n";
for ($c = 0; $c < $counter; $c++)
{
$next = 0;
for ($d = $c+1; $d < $counter && @order[$d] >= @order[$c]; $d++)
{
if (@order[$d] == @order[$c])
{
@next[$c] = $d;
last;
}
}
printf OID_C " {%s%s,%s%3d, %d, %s%s}%s /* %3d */\n"
,' ' x @order[$c]
, @octet[$c]
, ' ' x (1 + $max_order - @order[$c])
, @next[$c]
, @order[$c+1] > @order[$c]
, @name[$c]
, ' ' x ($max_name - length(@name[$c]))
, $c != $counter-1 ? "," : " "
, $c;
}
print OID_C "};\n" ;
close OID_C;
+184
View File
@@ -0,0 +1,184 @@
0x02 "ITU-T Administration"
0x82 ""
0x06 "Germany ITU-T member"
0x01 "Deutsche Telekom AG"
0x0A ""
0x07 ""
0x14 "ND"
0x09 "data"
0x92 ""
0x26 ""
0x89 ""
0x93 ""
0xF2 ""
0x2C ""
0x64 "pilot"
0x01 "pilotAttributeType"
0x01 "UID"
0x19 "DC"
0x55 "X.500"
0x04 "X.509"
0x03 "CN"
0x04 "S"
0x05 "SN"
0x06 "C"
0x07 "L"
0x08 "ST"
0x0A "O"
0x0B "OU"
0x0C "T"
0x0D "D"
0x24 "userCertificate"
0x29 "N"
0x2A "G"
0x2B "I"
0x2D "ID"
0x48 "role" OID_ROLE
0x1D "id-ce"
0x09 "subjectDirectoryAttrs"
0x0E "subjectKeyIdentifier" OID_SUBJECT_KEY_ID
0x0F "keyUsage"
0x10 "privateKeyUsagePeriod"
0x11 "subjectAltName" OID_SUBJECT_ALT_NAME
0x12 "issuerAltName"
0x13 "basicConstraints" OID_BASIC_CONSTRAINTS
0x15 "reasonCode" OID_CRL_REASON_CODE
0x1F "crlDistributionPoints" OID_CRL_DISTRIBUTION_POINTS
0x20 "certificatePolicies"
0x23 "authorityKeyIdentifier" OID_AUTHORITY_KEY_ID
0x25 "extendedKeyUsage" OID_EXTENDED_KEY_USAGE
0x37 "targetInformation" OID_TARGET_INFORMATION
0x38 "noRevAvail" OID_NO_REV_AVAIL
0x2A ""
0x86 ""
0x48 ""
0x86 ""
0xF7 ""
0x0D "RSADSI"
0x01 "PKCS"
0x01 "PKCS-1"
0x01 "rsaEncryption" OID_RSA_ENCRYPTION
0x02 "md2WithRSAEncryption" OID_MD2_WITH_RSA
0x04 "md5WithRSAEncryption" OID_MD5_WITH_RSA
0x05 "sha-1WithRSAEncryption" OID_SHA1_WITH_RSA
0x0B "sha256WithRSAEncryption" OID_SHA256_WITH_RSA
0x0C "sha384WithRSAEncryption" OID_SHA384_WITH_RSA
0x0D "sha512WithRSAEncryption" OID_SHA512_WITH_RSA
0x07 "PKCS-7"
0x01 "data" OID_PKCS7_DATA
0x02 "signedData" OID_PKCS7_SIGNED_DATA
0x03 "envelopedData" OID_PKCS7_ENVELOPED_DATA
0x04 "signedAndEnvelopedData" OID_PKCS7_SIGNED_ENVELOPED_DATA
0x05 "digestedData" OID_PKCS7_DIGESTED_DATA
0x06 "encryptedData" OID_PKCS7_ENCRYPTED_DATA
0x09 "PKCS-9"
0x01 "E" OID_PKCS9_EMAIL
0x02 "unstructuredName"
0x03 "contentType" OID_PKCS9_CONTENT_TYPE
0x04 "messageDigest" OID_PKCS9_MESSAGE_DIGEST
0x05 "signingTime" OID_PKCS9_SIGNING_TIME
0x06 "counterSignature"
0x07 "challengePassword"
0x08 "unstructuredAddress"
0x0E "extensionRequest"
0x02 "digestAlgorithm"
0x02 "md2" OID_MD2
0x05 "md5" OID_MD5
0x03 "encryptionAlgorithm"
0x07 "3des-ede-cbc" OID_3DES_EDE_CBC
0x2B ""
0x06 "dod"
0x01 "internet"
0x04 "private"
0x01 "enterprise"
0x82 ""
0x37 "Microsoft"
0x0A ""
0x03 ""
0x03 "msSGC"
0x89 ""
0x31 ""
0x01 ""
0x01 ""
0x02 ""
0x02 ""
0x4B "TCGID"
0x05 "security"
0x05 "mechanisms"
0x07 "id-pkix"
0x01 "id-pe"
0x01 "authorityInfoAccess" OID_AUTHORITY_INFO_ACCESS
0x03 "id-kp"
0x01 "serverAuth"
0x02 "clientAuth"
0x03 "codeSigning"
0x04 "emailProtection"
0x05 "ipsecEndSystem"
0x06 "ipsecTunnel"
0x07 "ipsecUser"
0x08 "timeStamping"
0x09 "ocspSigning" OID_OCSP_SIGNING
0x08 "id-otherNames"
0x05 "xmppAddr" OID_XMPP_ADDR
0x0A "id-aca"
0x01 "authenticationInfo" OID_AUTHENTICATION_INFO
0x02 "accessIdentity" OID_ACCESS_IDENTITY
0x03 "chargingIdentity" OID_CHARGING_IDENTITY
0x04 "group" OID_GROUP
0x30 "id-ad"
0x01 "ocsp" OID_OCSP
0x01 "basic" OID_BASIC
0x02 "nonce" OID_NONCE
0x03 "crl" OID_CRL
0x04 "response" OID_RESPONSE
0x05 "noCheck" OID_NO_CHECK
0x06 "archiveCutoff" OID_ARCHIVE_CUTOFF
0x07 "serviceLocator" OID_SERVICE_LOCATOR
0x0E "oiw"
0x03 "secsig"
0x02 "algorithms"
0x07 "des-cbc" OID_DES_CBC
0x1A "sha-1" OID_SHA1
0x1D "sha-1WithRSASignature" OID_SHA1_WITH_RSA_OIW
0x24 "TeleTrusT"
0x03 "algorithm"
0x03 "signatureAlgorithm"
0x01 "rsaSignature"
0x02 "rsaSigWithripemd160"
0x03 "rsaSigWithripemd128"
0x04 "rsaSigWithripemd256"
0x60 ""
0x86 ""
0x48 ""
0x01 "organization"
0x65 "gov"
0x03 "csor"
0x04 "nistalgorithm"
0x02 "hashalgs"
0x01 "id-SHA-256"
0x02 "id-SHA-384"
0x03 "id-SHA-512"
0x86 ""
0xf8 ""
0x42 "netscape"
0x01 ""
0x01 "nsCertType"
0x03 "nsRevocationUrl" OID_NS_REVOCATION_URL
0x04 "nsCaRevocationUrl" OID_NS_CA_REVOCATION_URL
0x08 "nsCaPolicyUrl" OID_NS_CA_POLICY_URL
0x0d "nsComment" OID_NS_COMMENT
0x03 "directory"
0x01 ""
0x03 "employeeNumber"
0x04 "policy"
0x01 "nsSGC"
0x45 "verisign"
0x01 "pki"
0x09 "attributes"
0x02 "messageType" OID_PKI_MESSAGE_TYPE
0x03 "pkiStatus" OID_PKI_STATUS
0x04 "failInfo" OID_PKI_FAIL_INFO
0x05 "senderNonce" OID_PKI_SENDER_NONCE
0x06 "recipientNonce" OID_PKI_RECIPIENT_NONCE
0x07 "transID" OID_PKI_TRANS_ID
0x08 "extensionReq"
+1244
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More