This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
_pluto_adns
|
||||
pluto
|
||||
whack
|
||||
+1095
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+103
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 $<
|
||||
@@ -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 $<
|
||||
@@ -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 $<
|
||||
@@ -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 $<
|
||||
@@ -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 $<
|
||||
@@ -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
|
||||
*/
|
||||
@@ -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
|
||||
*/
|
||||
@@ -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
|
||||
*/
|
||||
@@ -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
|
||||
*/
|
||||
@@ -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
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
}
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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, "..");
|
||||
}
|
||||
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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*/
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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 */
|
||||
}
|
||||
@@ -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
@@ -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:
|
||||
*/
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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 */
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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_
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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 */
|
||||
};
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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
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
Reference in New Issue
Block a user