summaryrefslogtreecommitdiff
path: root/keyexchange/isakmpd-20041012/ike_auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyexchange/isakmpd-20041012/ike_auth.c')
-rw-r--r--keyexchange/isakmpd-20041012/ike_auth.c1167
1 files changed, 0 insertions, 1167 deletions
diff --git a/keyexchange/isakmpd-20041012/ike_auth.c b/keyexchange/isakmpd-20041012/ike_auth.c
deleted file mode 100644
index dcacb0e..0000000
--- a/keyexchange/isakmpd-20041012/ike_auth.c
+++ /dev/null
@@ -1,1167 +0,0 @@
-/* $OpenBSD: ike_auth.c,v 1.95 2004/08/08 19:11:06 deraadt Exp $ */
-/* $EOM: ike_auth.c,v 1.59 2000/11/21 00:21:31 angelos Exp $ */
-
-/*
- * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved.
- * Copyright (c) 1999 Niels Provos. All rights reserved.
- * Copyright (c) 1999 Angelos D. Keromytis. All rights reserved.
- * Copyright (c) 2000, 2001, 2003 Håkan Olsson. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * This code was written under funding by Ericsson Radio Systems.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <regex.h>
-#if defined (USE_KEYNOTE)
-#include <keynote.h>
-#endif
-#include <policy.h>
-
-#include "sysdep.h"
-
-#include "cert.h"
-#include "conf.h"
-#include "constants.h"
-#if defined (USE_DNSSEC)
-#include "dnssec.h"
-#endif
-#include "exchange.h"
-#include "gmp_util.h"
-#include "hash.h"
-#include "ike_auth.h"
-#include "ipsec.h"
-#include "ipsec_doi.h"
-#include "libcrypto.h"
-#include "log.h"
-#include "message.h"
-#include "monitor.h"
-#include "prf.h"
-#include "transport.h"
-#include "util.h"
-#include "key.h"
-#if defined (USE_X509)
-#include "x509.h"
-#endif
-
-#ifdef notyet
-static u_int8_t *enc_gen_skeyid(struct exchange *, size_t *);
-#endif
-static u_int8_t *pre_shared_gen_skeyid(struct exchange *, size_t *);
-
-static int pre_shared_decode_hash(struct message *);
-static int pre_shared_encode_hash(struct message *);
-
-#if defined (USE_X509) || defined (USE_KEYNOTE)
-static u_int8_t *sig_gen_skeyid(struct exchange *, size_t *);
-static int rsa_sig_decode_hash(struct message *);
-static int rsa_sig_encode_hash(struct message *);
-#endif
-
-#if defined (USE_RAWKEY)
-static int get_raw_key_from_file(int, u_int8_t *, size_t, RSA **);
-#endif
-
-static int ike_auth_hash(struct exchange *, u_int8_t *);
-
-static struct ike_auth ike_auth[] = {
- {
- IKE_AUTH_PRE_SHARED, pre_shared_gen_skeyid,
- pre_shared_decode_hash,
- pre_shared_encode_hash
- },
-#ifdef notdef
- {
- IKE_AUTH_DSS, sig_gen_skeyid,
- pre_shared_decode_hash,
- pre_shared_encode_hash
- },
-#endif
-#if defined (USE_X509) || defined (USE_KEYNOTE)
- {
- IKE_AUTH_RSA_SIG, sig_gen_skeyid,
- rsa_sig_decode_hash,
- rsa_sig_encode_hash
- },
-#endif
-#ifdef notdef
- {
- 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
- },
-#endif
-};
-
-struct ike_auth *
-ike_auth_get(u_int16_t id)
-{
- size_t i;
-
- for (i = 0; i < sizeof ike_auth / sizeof ike_auth[0]; i++)
- if (id == ike_auth[i].id)
- return &ike_auth[i];
- return 0;
-}
-
-/*
- * Find and decode the configured key (pre-shared or public) for the
- * peer denoted by ID. Stash the len in KEYLEN.
- */
-static void *
-ike_auth_get_key(int type, char *id, char *local_id, size_t *keylen)
-{
- char *key, *buf;
-#if defined (USE_X509) || defined (USE_KEYNOTE)
- int fd;
- char *keyfile;
-#if defined (USE_X509)
- FILE *keyfp;
- RSA *rsakey;
- size_t fsize;
-#endif
-#endif
-
- switch (type) {
- case IKE_AUTH_PRE_SHARED:
- /* Get the pre-shared key for our peer. */
- key = conf_get_str(id, "Authentication");
- if (!key && local_id)
- key = conf_get_str(local_id, "Authentication");
-
- if (!key) {
- log_print("ike_auth_get_key: "
- "no key found for peer \"%s\" or local ID \"%s\"",
- id, local_id);
- return 0;
- }
- /* If the key starts with 0x it is in hex format. */
- if (strncasecmp(key, "0x", 2) == 0) {
- *keylen = (strlen(key) - 1) / 2;
- buf = malloc(*keylen);
- if (!buf) {
- log_error("ike_auth_get_key: malloc (%lu) "
- "failed", (unsigned long)*keylen);
- return 0;
- }
- if (hex2raw(key + 2, (unsigned char *)buf, *keylen)) {
- free(buf);
- log_print("ike_auth_get_key: invalid hex key "
- "%s", key);
- return 0;
- }
- key = buf;
- } else {
- buf = key;
- key = strdup(buf);
- if (!key) {
- log_error("ike_auth_get_key: strdup() failed");
- return 0;
- }
- *keylen = strlen(key);
- }
- break;
-
- case IKE_AUTH_RSA_SIG:
-#if defined (USE_X509) || defined (USE_KEYNOTE)
-#if defined (USE_KEYNOTE)
- if (local_id && (keyfile = conf_get_str("KeyNote",
- "Credential-directory")) != 0) {
- struct stat sb;
- struct keynote_deckey dc;
- char *privkeyfile, *buf2;
- int pkflen;
- size_t size;
-
- pkflen = strlen(keyfile) + strlen(local_id) +
- sizeof PRIVATE_KEY_FILE + sizeof "//" - 1;
- privkeyfile = calloc(pkflen, sizeof(char));
- if (!privkeyfile) {
- log_print("ike_auth_get_key: failed to "
- "allocate %d bytes", pkflen);
- return 0;
- }
- snprintf(privkeyfile, pkflen, "%s/%s/%s", keyfile,
- local_id, PRIVATE_KEY_FILE);
- keyfile = privkeyfile;
-
- fd = monitor_open(keyfile, O_RDONLY, 0);
- if (fd < 0) {
- free(keyfile);
- goto ignorekeynote;
- }
-
- if (fstat(fd, &sb) < 0) {
- log_print("ike_auth_get_key: fstat failed");
- free(keyfile);
- close(fd);
- return 0;
- }
- size = (size_t)sb.st_size;
-
- buf = calloc(size + 1, sizeof(char));
- if (!buf) {
- log_print("ike_auth_get_key: failed allocating"
- " %lu bytes", (unsigned long)size + 1);
- free(keyfile);
- close(fd);
- return 0;
- }
- if (read(fd, buf, size) != (ssize_t)size) {
- free(buf);
- log_print("ike_auth_get_key: "
- "failed reading %lu bytes from \"%s\"",
- (unsigned long)size, keyfile);
- free(keyfile);
- close(fd);
- return 0;
- }
- close(fd);
-
- /* Parse private key string */
- buf2 = kn_get_string(buf);
- free(buf);
-
- if (!buf2 || kn_decode_key(&dc, buf2,
- KEYNOTE_PRIVATE_KEY) == -1) {
- if (buf2)
- free(buf2);
- log_print("ike_auth_get_key: failed decoding "
- "key in \"%s\"", keyfile);
- free(keyfile);
- return 0;
- }
- free(buf2);
-
- if (dc.dec_algorithm != KEYNOTE_ALGORITHM_RSA) {
- log_print("ike_auth_get_key: wrong algorithm "
- "type %d in \"%s\"", dc.dec_algorithm,
- keyfile);
- free(keyfile);
- kn_free_key(&dc);
- return 0;
- }
- free(keyfile);
- return dc.dec_key;
- }
-ignorekeynote:
-#endif /* USE_KEYNOTE */
-#ifdef USE_X509
- /* Otherwise, try X.509 */
- keyfile = conf_get_str("X509-certificates", "Private-key");
-
- fd = monitor_open(keyfile, O_RDONLY, 0);
- if (fd < 0) {
- log_print("ike_auth_get_key: failed opening \"%s\"",
- keyfile);
- return 0;
- }
-
- if (check_file_secrecy_fd(fd, keyfile, &fsize) < 0) {
- close(fd);
- return 0;
- }
-
- if ((keyfp = fdopen(fd, "r")) == NULL) {
- log_print("ike_auth_get_key: fdopen failed");
- close(fd);
- return 0;
- }
-#if SSLEAY_VERSION_NUMBER >= 0x00904100L
- rsakey = PEM_read_RSAPrivateKey(keyfp, NULL, NULL, NULL);
-#else
- rsakey = PEM_read_RSAPrivateKey(keyfp, NULL, NULL);
-#endif
- fclose(keyfp);
-
- if (!rsakey) {
- log_print("ike_auth_get_key: "
- "PEM_read_bio_RSAPrivateKey failed");
- return 0;
- }
- return rsakey;
-#endif /* USE_X509 */
-#endif /* USE_X509 || USE_KEYNOTE */
-
- default:
- log_print("ike_auth_get_key: unknown key type %d", type);
- return 0;
- }
-
- return key;
-}
-
-static u_int8_t *
-pre_shared_gen_skeyid(struct exchange *exchange, size_t *sz)
-{
- struct prf *prf;
- struct ipsec_exch *ie = exchange->data;
- u_int8_t *skeyid, *buf = 0;
- unsigned char *key;
- size_t keylen;
-
- /*
- * If we're the responder and have the initiator's ID (which is the
- * case in Aggressive mode), try to find the preshared key in the
- * section of the initiator's Phase 1 ID. This allows us to do
- * mobile user support with preshared keys.
- */
- if (!exchange->initiator && exchange->id_i) {
- switch (exchange->id_i[0]) {
- case IPSEC_ID_IPV4_ADDR:
- case IPSEC_ID_IPV6_ADDR:
- util_ntoa((char **) &buf,
- exchange->id_i[0] == IPSEC_ID_IPV4_ADDR ? AF_INET :
- AF_INET6, exchange->id_i + ISAKMP_ID_DATA_OFF -
- ISAKMP_GEN_SZ);
- if (!buf)
- return 0;
- break;
-
- case IPSEC_ID_FQDN:
- case IPSEC_ID_USER_FQDN:
- buf = calloc(exchange->id_i_len - ISAKMP_ID_DATA_OFF +
- ISAKMP_GEN_SZ + 1, sizeof(char));
- if (!buf) {
- log_print("pre_shared_gen_skeyid: malloc (%lu"
- ") failed",
- (unsigned long)exchange->id_i_len -
- ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1);
- return 0;
- }
- memcpy(buf,
- exchange->id_i + ISAKMP_ID_DATA_OFF -
- ISAKMP_GEN_SZ,
- exchange->id_i_len - ISAKMP_ID_DATA_OFF +
- ISAKMP_GEN_SZ);
- break;
-
- /* XXX Support more ID types ? */
- default:
- break;
- }
- }
- /*
- * Get the pre-shared key for our peer. This will work even if the key
- * has been passed to us through a mechanism like PFKEYv2.
- */
- key = ike_auth_get_key(IKE_AUTH_PRE_SHARED, exchange->name,
- (char *) buf, &keylen);
- if (buf)
- free(buf);
-
- /* Fail if no key could be found. */
- if (!key)
- return 0;
-
- /* Store the secret key for later policy processing. */
- exchange->recv_key = calloc(keylen + 1, sizeof(char));
- exchange->recv_keytype = ISAKMP_KEY_PASSPHRASE;
- if (!exchange->recv_key) {
- log_error("pre_shared_gen_skeyid: malloc (%lu) failed",
- (unsigned long)keylen);
- free(key);
- return 0;
- }
- memcpy(exchange->recv_key, key, keylen);
- exchange->recv_certtype = ISAKMP_CERTENC_NONE;
- free(key);
-
- prf = prf_alloc(ie->prf_type, ie->hash->type, exchange->recv_key,
- keylen);
- if (!prf)
- return 0;
-
- *sz = prf->blocksize;
- skeyid = malloc(*sz);
- if (!skeyid) {
- log_error("pre_shared_gen_skeyid: malloc (%lu) failed",
- (unsigned long)*sz);
- prf_free(prf);
- return 0;
- }
- prf->Init(prf->prfctx);
- prf->Update(prf->prfctx, exchange->nonce_i, exchange->nonce_i_len);
- prf->Update(prf->prfctx, exchange->nonce_r, exchange->nonce_r_len);
- prf->Final(skeyid, prf->prfctx);
- prf_free(prf);
- return skeyid;
-}
-
-#if defined (USE_X509) || defined (USE_KEYNOTE)
-/* Both DSS & RSA signature authentication use this algorithm. */
-static u_int8_t *
-sig_gen_skeyid(struct exchange *exchange, size_t *sz)
-{
- struct prf *prf;
- struct ipsec_exch *ie = exchange->data;
- u_int8_t *skeyid;
- unsigned char *key;
-
- key = malloc(exchange->nonce_i_len + exchange->nonce_r_len);
- if (!key)
- return 0;
- memcpy(key, exchange->nonce_i, exchange->nonce_i_len);
- memcpy(key + exchange->nonce_i_len, exchange->nonce_r,
- exchange->nonce_r_len);
-
- LOG_DBG((LOG_NEGOTIATION, 80, "sig_gen_skeyid: PRF type %d, hash %d",
- ie->prf_type, ie->hash->type));
- LOG_DBG_BUF((LOG_NEGOTIATION, 80,
- "sig_gen_skeyid: SKEYID initialized with",
- (u_int8_t *)key, exchange->nonce_i_len + exchange->nonce_r_len));
-
- prf = prf_alloc(ie->prf_type, ie->hash->type, key,
- exchange->nonce_i_len + exchange->nonce_r_len);
- free(key);
- if (!prf)
- return 0;
-
- *sz = prf->blocksize;
- skeyid = malloc(*sz);
- if (!skeyid) {
- log_error("sig_gen_skeyid: malloc (%lu) failed",
- (unsigned long)*sz);
- prf_free(prf);
- return 0;
- }
- LOG_DBG((LOG_NEGOTIATION, 80, "sig_gen_skeyid: g^xy length %lu",
- (unsigned long) ie->g_x_len));
- LOG_DBG_BUF((LOG_NEGOTIATION, 80,
- "sig_gen_skeyid: SKEYID fed with g^xy", ie->g_xy, ie->g_x_len));
-
- prf->Init(prf->prfctx);
- prf->Update(prf->prfctx, ie->g_xy, ie->g_x_len);
- prf->Final(skeyid, prf->prfctx);
- prf_free(prf);
- return skeyid;
-}
-#endif /* USE_X509 || USE_KEYNOTE */
-
-#ifdef notdef
-/*
- * Both standard and revised RSA encryption authentication use 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) {
- log_error("enc_gen_skeyid: malloc (%d) failed", *sz);
- 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;
-}
-#endif /* notdef */
-
-static int
-pre_shared_decode_hash(struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct ipsec_exch *ie = exchange->data;
- struct payload *payload;
- size_t hashsize = ie->hash->hashsize;
- char header[80];
- int initiator = exchange->initiator;
- u_int8_t **hash_p;
-
- /* Choose the right fields to fill-in. */
- hash_p = initiator ? &ie->hash_r : &ie->hash_i;
-
- payload = payload_first(msg, ISAKMP_PAYLOAD_HASH);
- if (!payload) {
- log_print("pre_shared_decode_hash: no HASH payload found");
- return -1;
- }
- /* Check that the hash is of the correct size. */
- if (GET_ISAKMP_GEN_LENGTH(payload->p) - ISAKMP_GEN_SZ != hashsize)
- return -1;
-
- /* XXX Need this hash be in the SA? */
- *hash_p = malloc(hashsize);
- if (!*hash_p) {
- log_error("pre_shared_decode_hash: malloc (%lu) failed",
- (unsigned long)hashsize);
- return -1;
- }
- memcpy(*hash_p, payload->p + ISAKMP_HASH_DATA_OFF, hashsize);
- snprintf(header, sizeof header, "pre_shared_decode_hash: HASH_%c",
- initiator ? 'R' : 'I');
- LOG_DBG_BUF((LOG_MISC, 80, header, *hash_p, hashsize));
-
- payload->flags |= PL_MARK;
- return 0;
-}
-
-#if defined (USE_X509) || defined (USE_KEYNOTE)
-/* 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;
- void *cert = 0;
- u_int8_t *rawcert = 0, **hash_p, **id_cert, *id;
- u_int32_t rawcertlen, *id_cert_len;
- RSA *key = 0;
- size_t hashsize = ie->hash->hashsize, id_len;
- char header[80];
- int len, initiator = exchange->initiator;
- int found = 0, n, i, id_found;
-#if defined (USE_DNSSEC)
- u_int8_t *rawkey = 0;
- u_int32_t rawkeylen;
-#endif
-
- /* 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 || id_len == 0) {
- log_print("rsa_sig_decode_hash: ID is missing");
- return -1;
- }
- /*
- * XXX Assume we should use the same kind of certification as the
- * remote... moreover, just use the first CERT payload to decide what
- * to use.
- */
- p = payload_first(msg, ISAKMP_PAYLOAD_CERT);
- if (!p)
- handler = cert_get(ISAKMP_CERTENC_KEYNOTE);
- else
- handler = cert_get(GET_ISAKMP_CERT_ENCODING(p->p));
- if (!handler) {
- log_print("rsa_sig_decode_hash: cert_get (%d) failed",
- p ? GET_ISAKMP_CERT_ENCODING(p->p) : -1);
- return -1;
- }
-#if defined (USE_POLICY) || defined (USE_KEYNOTE)
- /*
- * We need the policy session initialized now, so we can add
- * credentials etc.
- */
- exchange->policy_id = kn_init();
- if (exchange->policy_id == -1) {
- log_print("rsa_sig_decode_hash: failed to initialize policy "
- "session");
- return -1;
- }
-#endif /* USE_POLICY || USE_KEYNOTE */
-
- /* Obtain a certificate from our certificate storage. */
- if (handler->cert_obtain(id, id_len, 0, &rawcert, &rawcertlen)) {
- if (handler->id == ISAKMP_CERTENC_X509_SIG) {
- cert = handler->cert_get(rawcert, rawcertlen);
- if (!cert)
- LOG_DBG((LOG_CRYPTO, 50, "rsa_sig_decode_hash:"
- " certificate malformed"));
- else {
- if (!handler->cert_get_key(cert, &key)) {
- log_print("rsa_sig_decode_hash: "
- "decoding certificate failed");
- handler->cert_free(cert);
- } else {
- found++;
- LOG_DBG((LOG_CRYPTO, 40,
- "rsa_sig_decode_hash: using cert "
- "of type %d", handler->id));
- exchange->recv_cert = cert;
- exchange->recv_certtype = handler->id;
-#if defined (USE_POLICY)
- x509_generate_kn(exchange->policy_id,
- cert);
-#endif /* USE_POLICY */
- }
- }
- } else if (handler->id == ISAKMP_CERTENC_KEYNOTE)
- handler->cert_insert(exchange->policy_id, rawcert);
- free(rawcert);
- }
- /*
- * Walk over potential CERT payloads in this message.
- * XXX I believe this is the wrong spot for this. CERTs can appear
- * anytime.
- */
- for (p = payload_first(msg, ISAKMP_PAYLOAD_CERT); p;
- p = TAILQ_NEXT(p, link)) {
- p->flags |= PL_MARK;
-
- /*
- * When we have found a key, just walk over the rest, marking
- * them.
- */
- if (found)
- continue;
-
- handler = cert_get(GET_ISAKMP_CERT_ENCODING(p->p));
- if (!handler) {
- LOG_DBG((LOG_MISC, 30, "rsa_sig_decode_hash: "
- "no handler for %s CERT encoding",
- constant_name(isakmp_certenc_cst,
- GET_ISAKMP_CERT_ENCODING(p->p))));
- continue;
- }
- cert = handler->cert_get(p->p + ISAKMP_CERT_DATA_OFF,
- GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_CERT_DATA_OFF);
- if (!cert) {
- log_print("rsa_sig_decode_hash: "
- "can not get data from CERT");
- continue;
- }
- if (!handler->cert_validate(cert)) {
- handler->cert_free(cert);
- log_print("rsa_sig_decode_hash: received CERT can't "
- "be validated");
- continue;
- }
- if (GET_ISAKMP_CERT_ENCODING(p->p) ==
- ISAKMP_CERTENC_X509_SIG) {
- if (!handler->cert_get_subjects(cert, &n, &id_cert,
- &id_cert_len)) {
- handler->cert_free(cert);
- log_print("rsa_sig_decode_hash: can not get "
- "subject from CERT");
- continue;
- }
- id_found = 0;
- for (i = 0; i < n; i++)
- if (id_cert_len[i] == id_len &&
- id[0] == id_cert[i][0] &&
- memcmp(id + 4, id_cert[i] + 4, id_len - 4)
- == 0) {
- id_found++;
- break;
- }
- if (!id_found) {
- handler->cert_free(cert);
- log_print("rsa_sig_decode_hash: no CERT "
- "subject match the ID");
- free(id_cert);
- continue;
- }
- cert_free_subjects(n, id_cert, id_cert_len);
- }
- if (!handler->cert_get_key(cert, &key)) {
- handler->cert_free(cert);
- log_print("rsa_sig_decode_hash: decoding payload CERT "
- "failed");
- continue;
- }
- /* We validated the cert, cache it for later use. */
- handler->cert_insert(exchange->policy_id, cert);
-
- exchange->recv_cert = cert;
- exchange->recv_certtype = GET_ISAKMP_CERT_ENCODING(p->p);
-
-#if defined (USE_POLICY) || defined (USE_KEYNOTE)
- if (exchange->recv_certtype == ISAKMP_CERTENC_KEYNOTE) {
- struct keynote_deckey dc;
- char *pp;
- int dclen;
-
- dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
- dc.dec_key = key;
-
- pp = kn_encode_key(&dc, INTERNAL_ENC_PKCS1,
- ENCODING_HEX, KEYNOTE_PUBLIC_KEY);
- if (pp == NULL) {
- kn_free_key(&dc);
- log_print("rsa_sig_decode_hash: failed to "
- "ASCII-encode key");
- return -1;
- }
- dclen = strlen(pp) + sizeof "rsa-hex:";
- exchange->keynote_key = calloc(dclen, sizeof(char));
- if (!exchange->keynote_key) {
- free(pp);
- kn_free_key(&dc);
- log_print("rsa_sig_decode_hash: failed to "
- "allocate %d bytes", dclen);
- return -1;
- }
- snprintf(exchange->keynote_key, dclen, "rsa-hex:%s",
- pp);
- free(pp);
- }
-#endif
-
- found++;
- }
-
-#if defined (USE_DNSSEC)
- /*
- * If no certificate provided a key, try to find a validated DNSSEC
- * KEY.
- */
- if (!found) {
- rawkey = dns_get_key(IKE_AUTH_RSA_SIG, msg, &rawkeylen);
-
- /* We need to convert 'void *rawkey' into 'RSA *key'. */
- if (dns_RSA_dns_to_x509(rawkey, rawkeylen, &key) == 0)
- found++;
- else
- log_print("rsa_sig_decode_hash: KEY to RSA key "
- "conversion failed");
-
- if (rawkey)
- free(rawkey);
- }
-#endif /* USE_DNSSEC */
-
-#if defined (USE_RAWKEY)
- /* If we still have not found a key, try to read it from a file. */
- if (!found)
- if (get_raw_key_from_file(IKE_AUTH_RSA_SIG, id, id_len, &key)
- != -1)
- found++;
-#endif
-
- if (!found) {
- log_print("rsa_sig_decode_hash: no public key found");
- return -1;
- }
- p = payload_first(msg, ISAKMP_PAYLOAD_SIG);
- if (!p) {
- log_print("rsa_sig_decode_hash: missing signature payload");
- RSA_free(key);
- return -1;
- }
- /* Check that the sig is of the correct size. */
- len = GET_ISAKMP_GEN_LENGTH(p->p) - ISAKMP_SIG_SZ;
- if (len != RSA_size(key)) {
- RSA_free(key);
- log_print("rsa_sig_decode_hash: "
- "SIG payload length does not match public key");
- return -1;
- }
- *hash_p = malloc(len);
- if (!*hash_p) {
- RSA_free(key);
- log_error("rsa_sig_decode_hash: malloc (%d) failed", len);
- return -1;
- }
- len = RSA_public_decrypt(len, p->p + ISAKMP_SIG_DATA_OFF, *hash_p, key,
- RSA_PKCS1_PADDING);
- if (len == -1) {
- RSA_free(key);
- log_print("rsa_sig_decode_hash: RSA_public_decrypt () failed");
- return -1;
- }
- /* Store key for later use */
- exchange->recv_key = key;
- exchange->recv_keytype = ISAKMP_KEY_RSA;
-
- if (len != (int) hashsize) {
- free(*hash_p);
- *hash_p = 0;
- log_print("rsa_sig_decode_hash: len %lu != hashsize %lu",
- (unsigned long)len, (unsigned long)hashsize);
- return -1;
- }
- snprintf(header, sizeof header, "rsa_sig_decode_hash: HASH_%c",
- initiator ? 'R' : 'I');
- LOG_DBG_BUF((LOG_MISC, 80, header, *hash_p, hashsize));
-
- p->flags |= PL_MARK;
- return 0;
-}
-#endif /* USE_X509 || USE_KEYNOTE */
-
-static int
-pre_shared_encode_hash(struct message *msg)
-{
- struct exchange *exchange = msg->exchange;
- struct ipsec_exch *ie = exchange->data;
- size_t hashsize = ie->hash->hashsize;
- char header[80];
- int initiator = exchange->initiator;
- u_int8_t *buf;
-
- buf = ipsec_add_hash_payload(msg, hashsize);
- if (!buf)
- return -1;
-
- if (ike_auth_hash(exchange, buf + ISAKMP_HASH_DATA_OFF) == -1)
- return -1;
-
- snprintf(header, sizeof header, "pre_shared_encode_hash: HASH_%c",
- initiator ? 'I' : 'R');
- LOG_DBG_BUF((LOG_MISC, 80, header, buf + ISAKMP_HASH_DATA_OFF,
- hashsize));
- return 0;
-}
-
-#if defined (USE_X509) || defined (USE_KEYNOTE)
-/* 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, id_len;
- struct cert_handler *handler;
- char header[80];
- int initiator = exchange->initiator, idtype;
- u_int8_t *buf, *data, *buf2, *id;
- u_int32_t datalen;
- int32_t sigsize;
- void *sent_key;
-
- id = initiator ? exchange->id_i : exchange->id_r;
- id_len = initiator ? exchange->id_i_len : exchange->id_r_len;
-
- /* We may have been provided these by the kernel */
- buf = (u_int8_t *) conf_get_str(exchange->name, "Credentials");
- if (buf && (idtype = conf_get_num(exchange->name, "Credential_Type",
- -1) != -1)) {
- exchange->sent_certtype = idtype;
- handler = cert_get(idtype);
- if (!handler) {
- log_print("rsa_sig_encode_hash: cert_get (%d) failed",
- idtype);
- return -1;
- }
- exchange->sent_cert =
- handler->cert_from_printable((char *)buf);
- if (!exchange->sent_cert) {
- log_print("rsa_sig_encode_hash: failed to retrieve "
- "certificate");
- return -1;
- }
- handler->cert_serialize(exchange->sent_cert, &data, &datalen);
- if (!data) {
- log_print("rsa_sig_encode_hash: cert serialization "
- "failed");
- return -1;
- }
- goto aftercert; /* Skip all the certificate discovery */
- }
- /* XXX This needs to be configurable. */
- idtype = ISAKMP_CERTENC_KEYNOTE;
-
- /* Find a certificate with subjectAltName = id. */
- handler = cert_get(idtype);
- if (!handler) {
- idtype = ISAKMP_CERTENC_X509_SIG;
- handler = cert_get(idtype);
- if (!handler) {
- log_print("rsa_sig_encode_hash: cert_get(%d) failed",
- idtype);
- return -1;
- }
- }
- if (handler->cert_obtain(id, id_len, 0, &data, &datalen) == 0) {
- if (idtype == ISAKMP_CERTENC_KEYNOTE) {
- idtype = ISAKMP_CERTENC_X509_SIG;
- handler = cert_get(idtype);
- if (!handler) {
- log_print("rsa_sig_encode_hash: cert_get(%d) "
- "failed", idtype);
- return -1;
- }
- if (handler->cert_obtain(id, id_len, 0, &data,
- &datalen) == 0) {
- LOG_DBG((LOG_MISC, 10, "rsa_sig_encode_hash: "
- "no certificate to send"));
- goto skipcert;
- }
- } else {
- LOG_DBG((LOG_MISC, 10,
- "rsa_sig_encode_hash: no certificate to send"));
- goto skipcert;
- }
- }
- /* Let's store the certificate we are going to use */
- exchange->sent_certtype = idtype;
- exchange->sent_cert = handler->cert_get(data, datalen);
- if (!exchange->sent_cert) {
- free(data);
- log_print("rsa_sig_encode_hash: failed to get certificate "
- "from wire encoding");
- return -1;
- }
-aftercert:
-
- buf = realloc(data, ISAKMP_CERT_SZ + datalen);
- if (!buf) {
- log_error("rsa_sig_encode_hash: realloc (%p, %d) failed", data,
- ISAKMP_CERT_SZ + datalen);
- free(data);
- return -1;
- }
- memmove(buf + ISAKMP_CERT_SZ, buf, datalen);
- SET_ISAKMP_CERT_ENCODING(buf, idtype);
- if (message_add_payload(msg, ISAKMP_PAYLOAD_CERT, buf,
- ISAKMP_CERT_SZ + datalen, 1)) {
- free(buf);
- return -1;
- }
-skipcert:
-
- /* Again, we may have these from the kernel */
- buf = (u_int8_t *) conf_get_str(exchange->name, "PKAuthentication");
- if (buf) {
- key_from_printable(ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE,
- (char *)buf, &data, &datalen);
- if (!data) {
- log_print("rsa_sig_encode_hash: badly formatted RSA "
- "private key");
- return 0;
- }
- sent_key = key_internalize(ISAKMP_KEY_RSA,
- ISAKMP_KEYTYPE_PRIVATE, data, datalen);
- if (!sent_key) {
- log_print("rsa_sig_encode_hash: bad RSA private key "
- "from dynamic SA acquisition subsystem");
- return 0;
- }
- } else {
- /* Try through the regular means. */
- switch (id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ]) {
- case IPSEC_ID_IPV4_ADDR:
- case IPSEC_ID_IPV6_ADDR:
- util_ntoa((char **)&buf2,
- id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ] ==
- IPSEC_ID_IPV4_ADDR ? AF_INET : AF_INET6,
- id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ);
- if (!buf2)
- return 0;
- break;
-
- case IPSEC_ID_FQDN:
- case IPSEC_ID_USER_FQDN:
- buf2 = calloc(id_len - ISAKMP_ID_DATA_OFF +
- ISAKMP_GEN_SZ + 1, sizeof(char));
- if (!buf2) {
- log_print("rsa_sig_encode_hash: malloc (%lu) "
- "failed", (unsigned long)id_len -
- ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1);
- return 0;
- }
- memcpy(buf2, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
- id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ);
- break;
-
- /* XXX Support more ID types? */
- default:
- buf2 = 0;
- return 0;
- }
-
- sent_key = ike_auth_get_key(IKE_AUTH_RSA_SIG, exchange->name,
- (char *)buf2, 0);
- free(buf2);
-
- /* Did we find a key? */
- if (!sent_key) {
- log_print("rsa_sig_encode_hash: "
- "could not get private key");
- return -1;
- }
- }
-
- /* Enable RSA blinding. */
- if (RSA_blinding_on(sent_key, NULL) != 1) {
- log_error("rsa_sig_encode_hash: RSA_blinding_on () failed.");
- return -1;
- }
- /* XXX hashsize is not necessarily prf->blocksize. */
- buf = malloc(hashsize);
- if (!buf) {
- log_error("rsa_sig_encode_hash: malloc (%lu) failed",
- (unsigned long)hashsize);
- return -1;
- }
- if (ike_auth_hash(exchange, buf) == -1) {
- free(buf);
- return -1;
- }
- snprintf(header, sizeof header, "rsa_sig_encode_hash: HASH_%c",
- initiator ? 'I' : 'R');
- LOG_DBG_BUF((LOG_MISC, 80, header, buf, hashsize));
-
- data = malloc(RSA_size(sent_key));
- if (!data) {
- log_error("rsa_sig_encode_hash: malloc (%d) failed",
- RSA_size(sent_key));
- return -1;
- }
- sigsize = RSA_private_encrypt(hashsize, buf, data, sent_key,
- RSA_PKCS1_PADDING);
- if (sigsize == -1) {
- log_print("rsa_sig_encode_hash: "
- "RSA_private_encrypt () failed");
- if (data)
- free(data);
- free(buf);
- RSA_free(sent_key);
- return -1;
- }
- datalen = (u_int32_t) sigsize;
-
- free(buf);
-
- buf = realloc(data, ISAKMP_SIG_SZ + datalen);
- if (!buf) {
- log_error("rsa_sig_encode_hash: realloc (%p, %d) failed", data,
- ISAKMP_SIG_SZ + datalen);
- free(data);
- return -1;
- }
- memmove(buf + ISAKMP_SIG_SZ, buf, datalen);
-
- snprintf(header, sizeof header, "rsa_sig_encode_hash: SIG_%c",
- initiator ? 'I' : 'R');
- LOG_DBG_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)) {
- free(buf);
- return -1;
- }
- return 0;
-}
-#endif /* USE_X509 || USE_KEYNOTE */
-
-int
-ike_auth_hash(struct exchange *exchange, u_int8_t *buf)
-{
- struct ipsec_exch *ie = exchange->data;
- struct prf *prf;
- struct hash *hash = ie->hash;
- int initiator = exchange->initiator;
- u_int8_t *id;
- size_t id_len;
-
- /* Choose the right fields to fill-in. */
- id = initiator ? exchange->id_i : exchange->id_r;
- id_len = initiator ? exchange->id_i_len : exchange->id_r_len;
-
- /* Allocate the prf and start calculating our HASH. */
- prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len);
- if (!prf)
- return -1;
-
- prf->Init(prf->prfctx);
- prf->Update(prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len);
- prf->Update(prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len);
- prf->Update(prf->prfctx, exchange->cookies +
- (initiator ? ISAKMP_HDR_ICOOKIE_OFF : ISAKMP_HDR_RCOOKIE_OFF),
- ISAKMP_HDR_ICOOKIE_LEN);
- prf->Update(prf->prfctx, exchange->cookies +
- (initiator ? ISAKMP_HDR_RCOOKIE_OFF : ISAKMP_HDR_ICOOKIE_OFF),
- ISAKMP_HDR_ICOOKIE_LEN);
- prf->Update(prf->prfctx, ie->sa_i_b, ie->sa_i_b_len);
- prf->Update(prf->prfctx, id, id_len);
- prf->Final(buf, prf->prfctx);
- prf_free(prf);
- return 0;
-}
-
-#if defined (USE_RAWKEY)
-static int
-get_raw_key_from_file(int type, u_int8_t *id, size_t id_len, RSA **rsa)
-{
- char filename[FILENAME_MAX];
- char *fstr;
- FILE *keyfp;
-
- if (type != IKE_AUTH_RSA_SIG) { /* XXX More types? */
- LOG_DBG((LOG_NEGOTIATION, 20, "get_raw_key_from_file: "
- "invalid auth type %d\n", type));
- return -1;
- }
- *rsa = 0;
-
- fstr = conf_get_str("General", "Pubkey-directory");
- if (!fstr)
- fstr = CONF_DFLT_PUBKEY_DIR;
-
- if (snprintf(filename, sizeof filename, "%s/", fstr) >
- (int)sizeof filename - 1)
- return -1;
-
- fstr = ipsec_id_string(id, id_len);
- if (!fstr) {
- LOG_DBG((LOG_NEGOTIATION, 50, "get_raw_key_from_file: "
- "ipsec_id_string failed"));
- return -1;
- }
- strlcat(filename, fstr, sizeof filename - strlen(filename));
- free(fstr);
-
- /* If the file does not exist, fail silently. */
- keyfp = monitor_fopen(filename, "r");
- if (keyfp) {
- *rsa = PEM_read_RSA_PUBKEY(keyfp, NULL, NULL, NULL);
- fclose(keyfp);
- } else if (errno != ENOENT) {
- log_error("get_raw_key_from_file: monitor_fopen "
- "(\"%s\", \"r\") failed", filename);
- return -1;
- } else
- LOG_DBG((LOG_NEGOTIATION, 50,
- "get_raw_key_from_file: file %s not found", filename));
-
- return (*rsa ? 0 : -1);
-}
-#endif /* USE_RAWKEY */