diff options
Diffstat (limited to 'keyexchange/isakmpd-20041012/ike_auth.c')
-rw-r--r-- | keyexchange/isakmpd-20041012/ike_auth.c | 1167 |
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 */ |