Index: ca.c
===================================================================
RCS file: /cvs/src/sbin/iked/ca.c,v
retrieving revision 1.17
diff -u -r1.17 ca.c
--- ca.c	27 May 2011 12:01:02 -0000	1.17
+++ ca.c	31 Aug 2012 12:30:13 -0000
@@ -67,6 +67,8 @@
 int	 ca_x509_subjectaltname_cmp(X509 *, struct iked_static_id *);
 int	 ca_x509_subjectaltname(X509 *cert, struct iked_id *);
 int	 ca_key_serialize(EVP_PKEY *, struct iked_id *);
+struct ibuf * 
+	 ca_rsa_serialize(RSA *);
 int	 ca_dispatch_parent(int, struct privsep_proc *, struct imsg *);
 int	 ca_dispatch_ikev1(int, struct privsep_proc *, struct imsg *);
 int	 ca_dispatch_ikev2(int, struct privsep_proc *, struct imsg *);
@@ -85,6 +87,7 @@
 	X509_LOOKUP	*ca_certlookup;
 
 	struct iked_id	 ca_privkey;
+	RSA *ca_pubkey;
 };
 
 pid_t
@@ -148,6 +151,7 @@
 	struct iked		*env = p->p_env;
 	struct ca_store	*store = env->sc_priv;
 	u_int			 mode;
+	u_int8_t                 reqtype;
 
 	switch (imsg->hdr.type) {
 	case IMSG_CTL_RESET:
@@ -158,6 +162,43 @@
 			ca_reset(&env->sc_ps, store);
 		}
 		break;
+
+	case IMSG_CTL_REQTYPE:
+		log_debug("IMSG_CTL_REQTYPE");
+		IMSG_SIZE_CHECK(imsg, &reqtype);
+		memcpy(&reqtype, imsg->data, sizeof(reqtype));
+		if (reqtype != IKEV2_CERT_RSA_KEY 
+		    && reqtype != IKEV2_CERT_X509_CERT) {
+			log_warn("%s: unknown CERTREQ type configuration", 
+			    __func__);
+			return (-1);
+		}
+		log_debug("%s: setting CERTREQ type %d", __func__, reqtype);
+		
+		/* Has the type changed? */
+		if (reqtype != env->sc_certreqtype) {
+			struct iovec		 iov[1];
+			int			 iovcnt = 1;
+
+			env->sc_certreqtype = reqtype;
+	
+			/* 
+			 * We need to reload the certificates and compute
+			 * hashes if we have gone from RSA -> X.509.
+			 *
+			 * Otherwise, we just tell IKEv2 to change the type.
+			 */
+			if (env->sc_certreqtype == IKEV2_CERT_X509_CERT)
+				ca_reload(env);
+			else {
+				iov[0].iov_base = &env->sc_certreqtype;
+				iov[0].iov_len = sizeof(env->sc_certreqtype);
+				(void)proc_composev_imsg(env, PROC_IKEV2, 
+				    IMSG_CERTREQ, -1, iov, iovcnt);
+			}
+		}
+		break;
+		
 	default:
 		return (-1);
 	}
@@ -392,40 +433,51 @@
 		return (-1);
 	memcpy(&sh, ptr + sizeof(id), sizeof(sh));
 	memcpy(&type, ptr + sizeof(id) + sizeof(sh), sizeof(u_int8_t));
-	if (type != IKEV2_CERT_X509_CERT)
-		return (-1);
 
-	for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) {
-		if ((ca = ca_by_subjectpubkey(store->ca_cas,
-		    ptr + i, SHA_DIGEST_LENGTH)) == NULL) {
-			log_debug("%s: CA %d not found", __func__, n);
-			print_hex(ptr, i, SHA_DIGEST_LENGTH);
-			continue;
-		}
+	switch (type) {
+	case IKEV2_CERT_RSA_KEY:
+		if ((buf = ca_rsa_serialize(store->ca_pubkey)) == NULL)
+			return (-1);
+		break;
 
-		log_debug("%s: found CA %s", __func__, ca->name);
+	case IKEV2_CERT_X509_CERT:
+		for (n = 1; i < len; n++, i += SHA_DIGEST_LENGTH) {
+			if ((ca = ca_by_subjectpubkey(store->ca_cas,
+			    ptr + i, SHA_DIGEST_LENGTH)) == NULL) {
+				log_debug("%s: CA %d not found", __func__, n);
+				print_hex(ptr, i, SHA_DIGEST_LENGTH);
+				continue;
+			}
 
-		if ((cert = ca_by_issuer(store->ca_certs,
-		    X509_get_subject_name(ca), &id)) != NULL) {
-			/* XXX should we re-validate our own cert here? */
-			break;
-		}
+			log_debug("%s: found CA %s", __func__, ca->name);
 
-		log_debug("%s: no valid certificate for this CA", __func__);
-	}
-	if (ca == NULL || cert == NULL) {
-		log_warnx("%s: no valid local certificate found", __func__);
-		type = IKEV2_CERT_NONE;
-		ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2);
-		return (0);
-	}
+			if ((cert = ca_by_issuer(store->ca_certs,
+			    X509_get_subject_name(ca), &id)) != NULL) {
+				/* XXX should we re-validate our own cert here? */
+				break;
+			}
 
-	log_debug("%s: found local certificate %s", __func__, cert->name);
+			log_debug("%s: no valid certificate for this CA", __func__);
+		}
+		if (ca == NULL || cert == NULL) {
+			log_warnx("%s: no valid local certificate found", __func__);
+			type = IKEV2_CERT_NONE;
+			ca_setcert(env, &sh, NULL, type, NULL, 0, PROC_IKEV2);
+			return (0);
+		}
+		log_debug("%s: found local certificate %s", __func__, cert->name);
 
-	if ((buf = ca_x509_serialize(cert)) == NULL)
-		return (-1);
+		if ((buf = ca_x509_serialize(cert)) == NULL)
+			return (-1);
 
-	type = IKEV2_CERT_X509_CERT;
+		type = IKEV2_CERT_X509_CERT;		
+		break;
+		
+	default:
+		log_warn("%s: unknown cert type requested");
+		return (-1);
+	} /* switch cert type */
+	
 	ca_setcert(env, &sh, NULL, type,
 	    ibuf_data(buf), ibuf_size(buf), PROC_IKEV2);
 
@@ -505,7 +557,9 @@
 	u_int8_t		 md[EVP_MAX_MD_SIZE];
 	struct iovec		 iov[2];
 	int			 iovcnt = 2;
-
+	FILE                     *fp;
+	EVP_PKEY                 *pubkey;
+	
 	/*
 	 * Load CAs
 	 */
@@ -587,7 +641,14 @@
 	}
 
 	if (ibuf_length(env->sc_certreq)) {
-		env->sc_certreqtype = IKEV2_CERT_X509_CERT;
+		log_debug("certreqtype: %d", env->sc_certreqtype);
+		if (env->sc_certreqtype == IKEV2_CERT_X509_CERT) {
+			log_debug("X509");
+		}
+		if (env->sc_certreqtype == IKEV2_CERT_RSA_KEY) {
+			log_debug("Raw RSA");
+		}
+
 		iov[0].iov_base = &env->sc_certreqtype;
 		iov[0].iov_len = sizeof(env->sc_certreqtype);
 		iov[1].iov_base = ibuf_data(env->sc_certreq);
@@ -639,6 +700,28 @@
 		(void)ca_validate_cert(env, NULL, x509, 0);
 	}
 
+	/* Load public RSA key. */
+
+	if ((fp = fopen(IKED_PUBKEY, "r")) == NULL) {
+		log_warn("couldn't open file " IKED_PUBKEY);
+		goto done;
+	}
+
+	store->ca_pubkey = NULL;
+	pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
+	if (pubkey == NULL) {
+		log_warn("couldn't read public RSA key");
+		goto done;
+	}
+	if ((store->ca_pubkey = EVP_PKEY_get1_RSA(pubkey)) == NULL) {
+		log_warn("couldn't parse public RSA key");
+		goto done;
+	}
+	
+	log_debug("%s: loaded public RSA key file.", __func__);
+	
+done:
+	fclose(fp);
 	return (0);
 }
 
@@ -749,6 +832,27 @@
 	return (buf);
 }
 
+struct ibuf *
+ca_rsa_serialize(RSA *rsa)
+{
+	long		 len;
+	struct ibuf	*buf;
+	u_int8_t	*d = NULL;
+	BIO		*out;
+
+	if ((out = BIO_new(BIO_s_mem())) == NULL)
+		return (NULL);
+	if (!i2d_RSAPublicKey_bio(out, rsa)) {
+		BIO_free(out);
+		return (NULL);
+	}
+
+	len = BIO_get_mem_data(out, &d);
+	buf = ibuf_new(d, len);
+
+	return (buf);
+}
+
 int
 ca_key_serialize(EVP_PKEY *key, struct iked_id *id)
 {
@@ -866,14 +970,17 @@
 	}
 
 	lc_string(idstr);
+
 	if (strlcpy(file, IKED_PUBKEY_DIR, sizeof(file)) >= sizeof(file) ||
-	    strlcpy(file, idstr, sizeof(file)) >= sizeof(file))
+	    strlcat(file, idstr, sizeof(file)) >= sizeof(file))
 		goto done;
+		
+	log_info("%s: looking up %s", __func__, file);
 
-	log_debug("%s: looking up %s", __func__, file);
-
-	if ((fp = fopen(file, "r")) == NULL)
+	if ((fp = fopen(file, "r")) == NULL) {
+		log_info("%s: %s: %s", __func__, file, strerror(errno));
 		goto done;
+	}
 
 	localkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
 	fclose(fp);
Index: config.c
===================================================================
RCS file: /cvs/src/sbin/iked/config.c,v
retrieving revision 1.13
diff -u -r1.13 config.c
--- config.c	5 Jul 2011 19:59:00 -0000	1.13
+++ config.c	31 Aug 2012 12:30:13 -0000
@@ -432,6 +432,13 @@
 }
 
 int
+config_setreqtype(struct iked *env, u_int type)
+{
+	proc_compose_imsg(env, PROC_CERT, IMSG_CTL_REQTYPE, -1, &type, sizeof (type));
+	return (0);	
+}
+
+int
 config_setreset(struct iked *env, u_int mode, enum privsep_procid id)
 {
 	proc_compose_imsg(env, id, IMSG_CTL_RESET, -1, &mode, sizeof(mode));
Index: iked.c
===================================================================
RCS file: /cvs/src/sbin/iked/iked.c,v
retrieving revision 1.11
diff -u -r1.11 iked.c
--- iked.c	9 May 2011 11:15:18 -0000	1.11
+++ iked.c	31 Aug 2012 12:30:13 -0000
@@ -216,6 +216,9 @@
 	config_setcoupled(env, env->sc_decoupled ? 0 : 1);
 	config_setmode(env, env->sc_passive ? 1 : 0);
 
+	/* Set default CERTREQ type. */
+	config_setreqtype(env, env->sc_certreqtype);
+	
 	return (0);
 }
 
Index: iked.conf.5
===================================================================
RCS file: /cvs/src/sbin/iked/iked.conf.5,v
retrieving revision 1.15
diff -u -r1.15 iked.conf.5
--- iked.conf.5	3 Sep 2011 22:59:08 -0000	1.15
+++ iked.conf.5	31 Aug 2012 12:30:13 -0000
@@ -134,6 +134,14 @@
 .It Ic set decouple
 Don't load the negotiated SAs and flows from the kernel.
 This mode is only useful for testing and debugging.
+.It Ic set certreq Ar type
+Set the CERTREQ type to either X.509 (the default) or Raw RSA public
+keys with
+.Ar x509
+and
+.Ar rawrsa
+respectively.  This determines what kind of certificate we ask for from
+the peers.
 .It Ic user Ar name Ar password
 .Xr iked 8
 supports user-based authentication by tunneling the Extensible
Index: iked.h
===================================================================
RCS file: /cvs/src/sbin/iked/iked.h,v
retrieving revision 1.41
diff -u -r1.41 iked.h
--- iked.h	9 May 2011 11:15:18 -0000	1.41
+++ iked.h	31 Aug 2012 12:30:13 -0000
@@ -543,6 +543,7 @@
 int	 config_getcoupled(struct iked *, u_int);
 int	 config_setmode(struct iked *, u_int);
 int	 config_getmode(struct iked *, u_int);
+int      config_setreqtype(struct iked *, u_int);
 int	 config_setreset(struct iked *, u_int, enum privsep_procid);
 int	 config_getreset(struct iked *, struct imsg *);
 int	 config_setpolicy(struct iked *, struct iked_policy *,
Index: ikev2_pld.c
===================================================================
RCS file: /cvs/src/sbin/iked/ikev2_pld.c,v
retrieving revision 1.21
diff -u -r1.21 ikev2_pld.c
--- ikev2_pld.c	26 Jan 2011 16:59:24 -0000	1.21
+++ ikev2_pld.c	31 Aug 2012 12:30:14 -0000
@@ -544,9 +544,11 @@
 	if (!ikev2_msg_frompeer(msg))
 		return (0);
 
-	if (!len || (len % SHA_DIGEST_LENGTH) != 0) {
-		log_debug("%s: invalid certificate request", __func__);
-		return (-1);
+	if (cert.cert_type == IKEV2_CERT_X509_CERT) {
+		if (!len || (len % SHA_DIGEST_LENGTH) != 0) {
+			log_debug("%s: invalid certificate request", __func__);
+			return (-1);
+		}
 	}
 
 	if (msg->msg_sa == NULL)
Index: parse.y
===================================================================
RCS file: /cvs/src/sbin/iked/parse.y,v
retrieving revision 1.22
diff -u -r1.22 parse.y
--- parse.y	27 May 2011 12:01:02 -0000	1.22
+++ parse.y	31 Aug 2012 12:30:14 -0000
@@ -93,6 +93,7 @@
 static int		 rules = 0;
 static int		 passive = 0;
 static int		 decouple = 0;
+static int		 certreqtype = IKEV2_CERT_X509_CERT;
 
 struct ipsec_xf {
 	const char	*name;
@@ -331,6 +332,7 @@
 
 %token	FROM ESP AH IN PEER ON OUT TO SRCID DSTID RSA PSK PORT
 %token	FILENAME AUTHXF PRFXF ENCXF ERROR IKEV2 IKESA CHILDSA
+%token  CERTREQ X509 RAWRSA
 %token	PASSIVE ACTIVE ANY TAG TAP PROTO LOCAL GROUP NAME CONFIG EAP USER
 %token	IKEV1 FLOW SA TCPMD5 TUNNEL TRANSPORT COUPLE DECOUPLE SET
 %token	INCLUDE LIFETIME BYTES INET INET6 QUICK SKIP DEFAULT
@@ -394,6 +396,12 @@
 		| SET PASSIVE	{ passive = 1; }
 		| SET COUPLE	{ decouple = 0; }
 		| SET DECOUPLE	{ decouple = 1; }
+		| SET CERTREQ X509 {
+			certreqtype = IKEV2_CERT_X509_CERT;
+		}
+		| SET CERTREQ RAWRSA {
+			certreqtype = IKEV2_CERT_RSA_KEY;
+		}
 		;
 
 user		: USER STRING STRING		{
@@ -1023,6 +1031,7 @@
 		{ "any",		ANY },
 		{ "auth",		AUTHXF },
 		{ "bytes",		BYTES },
+		{ "certreq",		CERTREQ },
 		{ "childsa",		CHILDSA },
 		{ "config",		CONFIG },
 		{ "couple",		COUPLE },
@@ -1052,6 +1061,7 @@
 		{ "proto",		PROTO },
 		{ "psk",		PSK },
 		{ "quick",		QUICK },
+		{ "rawrsa",		RAWRSA },
 		{ "rsa",		RSA },
 		{ "sa",			SA },
 		{ "set",		SET },
@@ -1063,7 +1073,8 @@
 		{ "to",			TO },
 		{ "transport",		TRANSPORT },
 		{ "tunnel",		TUNNEL },
-		{ "user",		USER }
+		{ "user",		USER },
+		{ "x509",		X509 }
 	};
 	const struct keywords	*p;
 
@@ -1419,6 +1430,8 @@
 
 	env->sc_passive = passive ? 1 : 0;
 	env->sc_decoupled = decouple ? 1 : 0;
+
+	env->sc_certreqtype = certreqtype;
 
 	if (!rules)
 		log_warnx("%s: no valid configuration rules found",
Index: types.h
===================================================================
RCS file: /cvs/src/sbin/iked/types.h,v
retrieving revision 1.10
diff -u -r1.10 types.h
--- types.h	5 May 2011 12:17:10 -0000	1.10
+++ types.h	31 Aug 2012 12:30:14 -0000
@@ -33,7 +33,7 @@
 #define IKED_CA_DIR	"ca/"
 #define IKED_CRL_DIR	"crls/"
 #define IKED_CERT_DIR	"certs/"
-#define IKED_PUBKEY_DIR	"pubkey/"
+#define IKED_PUBKEY_DIR	"pubkeys/"
 #define IKED_PRIVKEY	IKED_CA "private/local.key"
 #define IKED_PUBKEY	"local.pub"
 
@@ -84,6 +84,7 @@
 	IMSG_CTL_NOTIFY,
 	IMSG_CTL_RELOAD,
 	IMSG_CTL_RESET,
+	IMSG_CTL_REQTYPE,
 	IMSG_CTL_COUPLE,
 	IMSG_CTL_DECOUPLE,
 	IMSG_CTL_ACTIVE,
