summaryrefslogtreecommitdiff
path: root/sbin/isakmpd/ike_auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'sbin/isakmpd/ike_auth.c')
-rw-r--r--sbin/isakmpd/ike_auth.c278
1 files changed, 276 insertions, 2 deletions
diff --git a/sbin/isakmpd/ike_auth.c b/sbin/isakmpd/ike_auth.c
index e961c862cc1..07481799a53 100644
--- a/sbin/isakmpd/ike_auth.c
+++ b/sbin/isakmpd/ike_auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ike_auth.c,v 1.5 1998/11/15 01:13:27 niklas Exp $ */
+/* $OpenBSD: ike_auth.c,v 1.6 1998/11/16 21:07:16 niklas Exp $ */
/*
* Copyright (c) 1998 Niklas Hallqvist. All rights reserved.
@@ -52,11 +52,14 @@
#include "pkcs.h"
#include "prf.h"
+static u_int8_t *enc_gen_skeyid (struct exchange *, size_t *);
static u_int8_t *pre_shared_gen_skeyid (struct exchange *, size_t *);
static u_int8_t *sig_gen_skeyid (struct exchange *, size_t *);
static int pre_shared_decode_hash (struct message *);
+static int rsa_sig_decode_hash (struct message *);
static int pre_shared_encode_hash (struct message *);
+static int rsa_sig_encode_hash (struct message *);
static int ike_auth_hash (struct exchange *, u_int8_t *);
@@ -65,7 +68,12 @@ static struct ike_auth ike_auth[] = {
pre_shared_encode_hash},
{ IKE_AUTH_DSS, sig_gen_skeyid, pre_shared_decode_hash,
pre_shared_encode_hash},
- /* XXX Here should be hooks to code patented in the US. */
+ { IKE_AUTH_RSA_SIG, sig_gen_skeyid, rsa_sig_decode_hash,
+ rsa_sig_encode_hash},
+ { IKE_AUTH_RSA_ENC, enc_gen_skeyid, pre_shared_decode_hash,
+ pre_shared_encode_hash},
+ { IKE_AUTH_RSA_ENC_REV, enc_gen_skeyid, pre_shared_decode_hash,
+ pre_shared_encode_hash},
};
struct ike_auth *
@@ -150,6 +158,42 @@ sig_gen_skeyid (struct exchange *exchange, size_t *sz)
return skeyid;
}
+/*
+ * Both standard and revised RSA encryption authentication uses this SKEYID
+ * computation.
+ */
+static u_int8_t *
+enc_gen_skeyid (struct exchange *exchange, size_t *sz)
+{
+ struct prf *prf;
+ struct ipsec_exch *ie = exchange->data;
+ struct hash *hash = ie->hash;
+ u_int8_t *skeyid;
+
+ hash->Init (hash->ctx);
+ hash->Update (hash->ctx, exchange->nonce_i, exchange->nonce_i_len);
+ hash->Update (hash->ctx, exchange->nonce_r, exchange->nonce_r_len);
+ hash->Final (hash->digest, hash->ctx);
+ prf = prf_alloc (ie->prf_type, hash->type, hash->digest, *sz);
+ if (!prf)
+ return 0;
+
+ *sz = prf->blocksize;
+ skeyid = malloc (*sz);
+ if (!skeyid)
+ {
+ prf_free (prf);
+ return 0;
+ }
+
+ prf->Init (prf->prfctx);
+ prf->Update (prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN);
+ prf->Final (skeyid, prf->prfctx);
+ prf_free (prf);
+
+ return skeyid;
+}
+
static int
pre_shared_decode_hash (struct message *msg)
{
@@ -187,6 +231,120 @@ pre_shared_decode_hash (struct message *msg)
return 0;
}
+/*
+ * Decrypt the HASH in SIG, we already need a parsed ID payload
+ */
+
+static int
+rsa_sig_decode_hash (struct message *msg)
+{
+ struct cert_handler *handler;
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ struct payload *p;
+ struct rsa_public_key key;
+ size_t hashsize = ie->hash->hashsize;
+ char header[80];
+ int initiator = exchange->initiator;
+ u_int8_t **hash_p, *id_cert, *id;
+ u_int16_t len;
+ u_int32_t id_cert_len;
+ size_t id_len;
+
+ /* Choose the right fields to fill-in. */
+ hash_p = initiator ? &ie->hash_r : &ie->hash_i;
+ id = initiator ? exchange->id_r : exchange->id_i;
+ id_len = initiator ? exchange->id_r_len : exchange->id_i_len;
+
+ if (id == NULL || id_len == 0)
+ {
+ log_print ("rsa_sig_decode_hash: no ID in sa");
+ return -1;
+ }
+
+ /* Just bother with the ID data field. */
+ id += ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+ id_len -= ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ;
+
+ p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_CERT]);
+ if (!p)
+ return -1;
+
+ if ((handler = cert_get (GET_ISAKMP_CERT_ENCODING(p->p))) == NULL)
+ {
+ log_print ("rsa_sig_decode_hash: no handler for CERT encoding");
+ return -1;
+ }
+
+ /* XXX - this assumes IPv4 here */
+ if (!handler->cert_get_subject (p->p + ISAKMP_CERT_DATA_OFF,
+ GET_ISAKMP_GEN_LENGTH(p->p) -
+ ISAKMP_CERT_DATA_OFF,
+ &id_cert, &id_cert_len))
+ {
+ log_print ("rsa_sig_decode_hash: can not get subject from CERT");
+ return -1;
+ }
+
+ if (id_cert_len != id_len || memcmp (id, id_cert, id_len))
+ {
+ log_print ("rsa_sig_decode_hash: CERT subject does not match ID");
+ free (id_cert);
+ return -1;
+ }
+ free (id_cert);
+
+ if (!handler->cert_get_key (p->p + ISAKMP_CERT_DATA_OFF,
+ GET_ISAKMP_GEN_LENGTH(p->p) -
+ ISAKMP_CERT_DATA_OFF,
+ &key))
+ {
+ log_print ("rsa_sig_decode_hash: decoding payload CERT failed");
+ return -1;
+ }
+
+ p->flags |= PL_MARK;
+
+ p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SIG]);
+ if (!p)
+ {
+ pkcs_free_public_key (&key);
+ return -1;
+ }
+
+ /* Check that the sig is of the correct size. */
+ if (GET_ISAKMP_GEN_LENGTH (p->p) - ISAKMP_SIG_SZ != mpz_sizeinoctets (key.n))
+ {
+ pkcs_free_public_key (&key);
+ log_print ("rsa_sig_decode_hash: SIG payload length does not match "
+ "public key");
+ return -1;
+ }
+
+ if (!pkcs_rsa_decrypt (PKCS_PRIVATE, key.n, key.e,
+ p->p + ISAKMP_SIG_DATA_OFF, hash_p, &len))
+ {
+ pkcs_free_public_key (&key);
+ return -1;
+ }
+
+ pkcs_free_public_key (&key);
+
+ if (len != hashsize)
+ {
+ free (*hash_p);
+ *hash_p = NULL;
+ return -1;
+ }
+
+ snprintf (header, 80, "rsa_sig_decode_hash: HASH_%c", initiator ? 'R' : 'I');
+ log_debug_buf (LOG_MISC, 80, header, *hash_p, hashsize);
+
+ p->flags |= PL_MARK;
+
+ return 0;
+}
+
static int
pre_shared_encode_hash (struct message *msg)
{
@@ -226,6 +384,122 @@ pre_shared_encode_hash (struct message *msg)
return 0;
}
+
+/* Encrypt the HASH into a SIG type */
+
+static int
+rsa_sig_encode_hash (struct message *msg)
+{
+ struct exchange *exchange = msg->exchange;
+ struct ipsec_exch *ie = exchange->data;
+ size_t hashsize = ie->hash->hashsize;
+ struct cert_handler *handler;
+ struct rsa_private_key key;
+ char header[80];
+ int initiator = exchange->initiator;
+ u_int8_t *buf, *asn, *data;
+ u_int32_t asnlen, datalen;
+ char *keyfile;
+
+ /* XXX - this needs to be configureable */
+ handler = cert_get (ISAKMP_CERTENC_X509_SIG);
+ if (handler == NULL)
+ {
+ /* XXX - Log? */
+ return -1;
+ }
+ /* XXX - implicitly uses exchange->id_{i,r} */
+ if (!handler->cert_obtain (exchange, NULL, &data, &datalen))
+ {
+ /* XXX - Log? */
+ return -1;
+ }
+
+ buf = realloc (data, ISAKMP_CERT_SZ + datalen);
+ if (buf == NULL)
+ {
+ /* XXX Log? */
+ free (data);
+ return -1;
+ }
+ memmove (buf + ISAKMP_CERT_SZ, buf, datalen);
+ SET_ISAKMP_CERT_ENCODING (buf, ISAKMP_CERTENC_X509_SIG);
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_CERT, buf,
+ ISAKMP_CERT_SZ + datalen, 1))
+ {
+ /* XXX Log? */
+ free (buf);
+ return -1;
+ }
+
+ /* XXX - do we want to store our files in ASN.1 ? */
+ keyfile = conf_get_str ("rsa_sig", "privkey");
+ if (!asn_get_from_file (keyfile, &asn, &asnlen))
+ {
+ /* XXX Log? */
+ return -1;
+ }
+
+ if (!pkcs_private_key_from_asn (&key, asn, asnlen))
+ {
+ /* XXX Log? */
+ free (asn);
+ return -1;
+ }
+ free (asn);
+
+ /* XXX - hashsize is not necessarily prf->blocksize */
+ buf = malloc (hashsize);
+ if (!buf)
+ {
+ /* XXX Log? */
+ pkcs_free_private_key (&key);
+ return -1;
+ }
+
+ if (ike_auth_hash (exchange, buf) == -1)
+ {
+ /* XXX Log? */
+ free (buf);
+ pkcs_free_private_key (&key);
+ return -1;
+ }
+
+ snprintf (header, 80, "rsa_sig_encode_hash: HASH_%c", initiator ? 'I' : 'R');
+ log_debug_buf (LOG_MISC, 80, header, buf, hashsize);
+
+ if (!pkcs_rsa_encrypt (PKCS_PRIVATE, key.n, key.e, buf, hashsize,
+ &data, &datalen))
+ {
+ free (buf);
+ pkcs_free_private_key (&key);
+ return -1;
+ }
+ pkcs_free_private_key (&key);
+ free (buf);
+
+ buf = realloc (data, ISAKMP_SIG_SZ + datalen);
+ if (!buf)
+ {
+ /* XXX Log? */
+ free (data);
+ return -1;
+ }
+ memmove (buf + ISAKMP_SIG_SZ, buf, datalen);
+
+ snprintf (header, 80, "rsa_sig_encode_hash: SIG_%c", initiator ? 'I' : 'R');
+ log_debug_buf (LOG_MISC, 80, header, buf + ISAKMP_SIG_DATA_OFF, datalen);
+ if (message_add_payload (msg, ISAKMP_PAYLOAD_SIG, buf,
+ ISAKMP_SIG_SZ + datalen, 1))
+ {
+ /* XXX Log? */
+ free (buf);
+ return -1;
+ }
+
+ return 0;
+}
+
int
ike_auth_hash (struct exchange *exchange, u_int8_t *buf)
{