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	27 Sep 2012 16:01:33 -0000
@@ -67,10 +67,27 @@
 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 *);
 
+static struct buffer * 
+	 buffer_alloc(u_int len);
+static void 
+	 buffer_free(struct buffer *buffer);
+static void 
+	 put_u32(void *vp, u_int32_t v);
+static int 
+	 buffer_int(struct buffer *buffer, u_int value);
+static int 
+	 buffer_string(struct buffer *buffer, const void *buf, u_int len);
+static int 
+	 buffer_bignum(struct buffer *buffer, BIGNUM *bn);
+static int
+	fingerprint(EVP_PKEY *key, char *mdstr);
+
 static struct privsep_proc procs[] = {
 	{ "parent",	PROC_PARENT,	ca_dispatch_parent },
 	{ "ikev1",	PROC_IKEV1,	ca_dispatch_ikev1 },
@@ -85,6 +102,14 @@
 	X509_LOOKUP	*ca_certlookup;
 
 	struct iked_id	 ca_privkey;
+	RSA		*ca_pubkey;
+};
+
+struct buffer
+{
+	u_char	*buf;	/* Data. */
+	u_int	 len;	/* Length of data in bytes. */
+	u_int	 size;	/* Allocated size of buf. */
 };
 
 pid_t
@@ -148,6 +173,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 +184,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);
 	}
@@ -353,11 +416,23 @@
 		break;
 	}
 
-	if (ret == 0)
-		cmd = IMSG_CERTVALID;
-	else
+	switch (ret) {
+	case -2:
+		cmd = IMSG_CERTNOTFOUND;
+		break;
+	case -1:
 		cmd = IMSG_CERTINVALID;
-
+		break;
+	case 0:
+		cmd = IMSG_CERTVALID;
+		break;
+	default:
+		cmd = IMSG_CERTINVALID;		
+		log_debug("%s: unknown return from key validation %d", 
+		    __func__, ret);
+		break;
+	}
+	
 	iov[0].iov_base = &sh;
 	iov[0].iov_len = sizeof(sh);
 	iov[1].iov_base = &type;
@@ -392,40 +467,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 +591,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 +675,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 +734,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 +866,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)
 {
@@ -825,6 +963,7 @@
 	FILE		*fp = NULL;
 	char		 idstr[IKED_ID_SIZE];
 	char		 file[MAXPATHLEN];
+	char		 mdstr[41];
 	struct iked_id	 idp;
 
 	if (len == 0 && data == NULL)
@@ -835,7 +974,8 @@
 	case IKEV2_ID_FQDN:
 	case IKEV2_ID_UFQDN:
 	case IKEV2_ID_IPV6:
-		break;
+	case IKEV2_ID_PUBLICKEY:		
+		break;		
 	default:
 		/* Some types like ASN1_DN will not be mapped to file names */
 		return (-1);
@@ -865,15 +1005,46 @@
 			goto sslerr;
 	}
 
-	lc_string(idstr);
-	if (strlcpy(file, IKED_PUBKEY_DIR, sizeof(file)) >= sizeof(file) ||
-	    strlcpy(file, idstr, sizeof(file)) >= sizeof(file))
-		goto done;
+	if (id->id_type == IKEV2_ID_PUBLICKEY) {
+		if (fingerprint(peerkey, mdstr) != 0) {
+			log_warn("%s: couldn't compute fingerprint", __func__);
+			goto done;
+		}
+		if (strlcpy(file, IKED_FP_DIR, sizeof(file)) >= sizeof(file)
+		    || strlcat(file, mdstr, sizeof(file)) >= sizeof(file))
+			goto done;
+	} else {
+		lc_string(idstr);
 
-	log_debug("%s: looking up %s", __func__, file);
+		if (strlcpy(file, IKED_PUBKEY_DIR, sizeof(file)) >= sizeof(file) ||
+		    strlcat(file, idstr, sizeof(file)) >= sizeof(file))
+		goto done;
+	}
+	
+	log_info("%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));
+		if (id->id_type == IKEV2_ID_PUBLICKEY) {
+			/* Check for wildcard. */
+			if (strlcpy(file, IKED_BTNSWILD, sizeof(file)) 
+			    >= sizeof(file))
+				goto done;
+			
+			if ((fp = fopen(file, "r")) == NULL) {
+				/* No wildcard and no file. Invalid cert. */
+				ret = -1;
+			} else {
+				/* Wildcard BTNS allowed: Key OK. */
+				log_info("%s: BTNS wildcard match", __func__);
+				ret = 0;
+			}
+		} else {
+			/* Key file not found. */
+			ret = -2;
+		}
 		goto done;
+	}
 
 	localkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
 	fclose(fp);
@@ -1124,4 +1295,160 @@
 	while ((error = ERR_get_error()) != 0)
 		log_warn("%s: %.100s", __func__,
 		    ERR_error_string(error, NULL));
+}
+
+
+static struct buffer *
+buffer_alloc(u_int len)
+{
+	struct buffer *buffer;
+	
+	if (NULL == (buffer = calloc(1, sizeof (struct buffer)))) {
+		return NULL;
+	}
+	buffer->len = 0;
+	buffer->size = len;
+	buffer->buf = malloc(len);
+	if (buffer->buf == NULL) {
+		free(buffer);
+		return NULL;
+	}
+
+	return buffer;
+}
+
+static void
+buffer_free(struct buffer *buffer)
+{
+	if (buffer == NULL)
+		return;
+	if (buffer->buf != NULL)
+		free(buffer->buf);
+
+	free(buffer);
+}
+
+static void
+put_u32(void *vp, u_int32_t v)
+{
+	u_char *p = (u_char *)vp;
+
+	p[0] = (u_char)(v >> 24) & 0xff;
+	p[1] = (u_char)(v >> 16) & 0xff;
+	p[2] = (u_char)(v >> 8) & 0xff;
+	p[3] = (u_char)v & 0xff;
+}
+
+static int
+buffer_int(struct buffer *buffer, u_int value)
+{
+	char buf[4];
+
+        if (buffer->len + 4 > buffer->size)
+            return (-1);
+        
+	put_u32(buf, value);
+	memcpy(&buffer->buf[buffer->len], buf, 4);
+	buffer->len += 4;
+
+        return (0);
+}
+
+static int
+buffer_string(struct buffer *buffer, const void *buf, u_int len)
+{
+        if (buffer->len + len > buffer->size)
+            return (-1);
+    
+	memcpy(&buffer->buf[buffer->len], buf, len);
+	buffer->len += len;
+
+        return (0);
+}
+
+static int
+buffer_bignum(struct buffer *buffer, BIGNUM *bn)
+{
+	u_int len;
+	int oi;
+	unsigned char *buf;
+	
+	len = BN_num_bytes(bn);
+        if (buffer->len + len > buffer->size) {
+            return (-1);
+        }
+
+	if (NULL == (buf = malloc(len))) {
+		return (-1);
+	}
+	oi = BN_bn2bin(bn, buf);
+	if (oi < 0 || (u_int)oi != len) {
+		fprintf(stderr, " BN_bn2bin() failed: "
+		      "oi %d != bin_size %d\n", oi, len);
+		free(buf);
+		return (-1);
+	}
+	buffer_string(buffer, buf, len);
+	free(buf);
+
+	return (0);
+}
+
+static int
+fingerprint(EVP_PKEY *key, char *mdstr)
+{
+	RSA		*rsa = NULL;
+	struct buffer	*buffer = NULL;
+	unsigned char 	*md;
+	u_int32_t 	 elen, nlen;
+	u_int		 bytes;
+	int		 ret;
+	
+	rsa = EVP_PKEY_get1_RSA(key);
+	elen = BN_num_bytes(rsa->e);
+	nlen = BN_num_bytes(rsa->n);
+
+	/* Allocate space for two bignums and their length. */
+	bytes = elen + nlen + 2 * 4;
+	if (NULL == (buffer = buffer_alloc(bytes))) {
+		log_warn("%s: buffer_alloc: out of memory", __func__);
+		return (-1);
+	}
+
+	/* RSA exponent e. First length, then e itself. */
+	if (buffer_int(buffer, elen) != 0) {
+	    ret = -1;
+            goto done;
+        }
+	if (buffer_bignum(buffer, rsa->e) != 0) {
+	    ret = -1;
+	    goto done;
+        }
+        
+	/* RSA modulus n. First length, then n itself. */
+	if (buffer_int(buffer, nlen) != 0) {
+	    ret = -1;	    
+            goto done;
+        }
+	if (buffer_bignum(buffer, rsa->n) != 0) {
+	    ret = -1;	    
+            goto done;
+        }
+
+	/* SHA-1 digest of both bignums and their length. */
+	md = SHA1(buffer->buf, buffer->len, NULL);
+	snprintf(mdstr, 41, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
+	    "%02x%02x%02x%02x%02x%02x%02x%02x", md[0], md[1], md[2],
+	    md[3], md[4], md[5], md[6], md[7], md[8], md[9], md[10],
+	    md[11], md[12], md[13], md[14], md[15], md[16], md[17],
+            md[18], md[19]);
+
+	ret = 0;
+done:
+	if (buffer != NULL)
+		buffer_free(buffer);
+	if (rsa != NULL)
+		free(rsa);
+
+	return ret;
 }
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	27 Sep 2012 16:01:33 -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	27 Sep 2012 16:01:33 -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	27 Sep 2012 16:01:33 -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
@@ -422,6 +430,11 @@
 .Ic srcid ,
 but instead specifies the ID to be used
 by the remote peer.
+.It Ic btns
+The optional 
+.Ic btns 
+parameter defines if peers are allowed to use unvalidated public keys
+as defined in Better-than-nothing Security (RFC 5386).
 .It Ic lifetime Ar time Op Ic bytes Ar bytes
 The optional
 .Ic lifetime
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	27 Sep 2012 16:01:33 -0000
@@ -190,6 +190,7 @@
 
 struct iked_auth {
 	u_int8_t	auth_method;
+	u_int8_t	auth_btns_allowed;
 	u_int8_t	auth_eap;			/* optional EAP */
 	u_int8_t	auth_length;			/* zero if EAP */
 	u_int8_t	auth_data[IKED_PSK_SIZE];
@@ -543,6 +544,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.c
===================================================================
RCS file: /cvs/src/sbin/iked/ikev2.c,v
retrieving revision 1.57
diff -u -r1.57 ikev2.c
--- ikev2.c	5 Jul 2011 01:28:06 -0000	1.57
+++ ikev2.c	27 Sep 2012 16:01:34 -0000
@@ -189,7 +189,8 @@
 	u_int8_t		*ptr;
 	size_t			 len;
 	struct iked_id		*id = NULL;
-
+	struct iked_id	        *certid = NULL;
+	
 	switch (imsg->hdr.type) {
 	case IMSG_CERTREQ:
 		IMSG_SIZE_CHECK(imsg, &type);
@@ -209,6 +210,7 @@
 		break;
 	case IMSG_CERTVALID:
 	case IMSG_CERTINVALID:
+	case IMSG_CERTNOTFOUND:		
 		memcpy(&sh, imsg->data, sizeof(sh));
 		memcpy(&type, (u_int8_t *)imsg->data + sizeof(sh),
 		    sizeof(type));
@@ -223,6 +225,38 @@
 			log_debug("%s: peer certificate is valid", __func__);
 			sa_stateflags(sa, IKED_REQ_VALID);
 			sa_state(env, sa, IKEV2_STATE_VALID);
+		} else if (imsg->hdr.type == IMSG_CERTNOTFOUND) {
+			/* Check if we can do BTNS. */
+			if (sa->sa_policy->pol_auth.auth_btns_allowed) {
+				log_debug("%s: peer key not found but "
+				    "BTNS allowed", __func__);
+				
+				/* Convert peer's ID to type PUBLICKEY */
+				if (sa->sa_hdr.sh_initiator) {
+					sa->sa_rid.id_type = IKEV2_ID_PUBLICKEY;
+					id = &sa->sa_rid;
+					certid = &sa->sa_rcert;
+				} else {
+					sa->sa_iid.id_type = IKEV2_ID_PUBLICKEY;
+					id = &sa->sa_iid;
+					certid = &sa->sa_icert;
+				}
+				
+				/* 
+				 * Send back the converted ID to CA process so 
+				 * it can check if there's a fingerprint match 
+				 * or if wilcards are allowed. 
+				 */
+				ca_setcert(env, &sa->sa_hdr,
+				    id, certid->id_type,
+				    ibuf_data(certid->id_buf),
+				    ibuf_length(certid->id_buf), PROC_CERT);
+		
+				return (0);
+
+			} else {
+				log_warnx("%s: peer key not found", __func__);
+			}
 		} else {
 			log_warnx("%s: peer certificate is invalid", __func__);
 		}
Index: ikev2.h
===================================================================
RCS file: /cvs/src/sbin/iked/ikev2.h,v
retrieving revision 1.6
diff -u -r1.6 ikev2.h
--- ikev2.h	3 Jul 2010 16:59:35 -0000	1.6
+++ ikev2.h	27 Sep 2012 16:01:34 -0000
@@ -379,6 +379,7 @@
 #define IKEV2_ID_ASN1_GN	10	/* RFC4306 */
 #define IKEV2_ID_KEY_ID		11	/* RFC4306 */
 #define IKEV2_ID_FC_NAME	12	/* RFC4595 */
+#define IKEV2_ID_PUBLICKEY	13	/* RFC5386 - not used on the wire */
 
 extern struct iked_constmap ikev2_id_map[];
 
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	27 Sep 2012 16:01:34 -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	27 Sep 2012 16:01:34 -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;
@@ -329,8 +330,9 @@
 
 %}
 
-%token	FROM ESP AH IN PEER ON OUT TO SRCID DSTID RSA PSK PORT
+%token	FROM ESP AH IN PEER ON OUT TO SRCID DSTID RSA BTNS 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		{
@@ -751,10 +759,17 @@
 ikeauth		: /* empty */			{
 			$$.auth_method = IKEV2_AUTH_RSA_SIG;
 			$$.auth_length = 0;
+			$$.auth_btns_allowed = 0;
 		}
 		| RSA				{
 			$$.auth_method = IKEV2_AUTH_RSA_SIG;
 			$$.auth_length = 0;
+			$$.auth_btns_allowed = 0;
+		}
+		| BTNS				{
+			$$.auth_method = IKEV2_AUTH_RSA_SIG;
+			$$.auth_length = 0;
+			$$.auth_btns_allowed = 1;
 		}
 		| PSK keyspec			{
 			memcpy(&$$, &$2, sizeof($$));
@@ -1022,7 +1037,9 @@
 		{ "ah",			AH },
 		{ "any",		ANY },
 		{ "auth",		AUTHXF },
+		{ "btns",		BTNS },
 		{ "bytes",		BYTES },
+		{ "certreq",		CERTREQ },
 		{ "childsa",		CHILDSA },
 		{ "config",		CONFIG },
 		{ "couple",		COUPLE },
@@ -1052,6 +1069,7 @@
 		{ "proto",		PROTO },
 		{ "psk",		PSK },
 		{ "quick",		QUICK },
+		{ "rawrsa",		RAWRSA },
 		{ "rsa",		RSA },
 		{ "sa",			SA },
 		{ "set",		SET },
@@ -1063,7 +1081,8 @@
 		{ "to",			TO },
 		{ "transport",		TRANSPORT },
 		{ "tunnel",		TUNNEL },
-		{ "user",		USER }
+		{ "user",		USER },
+		{ "x509",		X509 }
 	};
 	const struct keywords	*p;
 
@@ -1419,6 +1438,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	27 Sep 2012 16:01:34 -0000
@@ -33,9 +33,11 @@
 #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_FP_DIR     "pubkeys/fp/"
 #define IKED_PRIVKEY	IKED_CA "private/local.key"
 #define IKED_PUBKEY	"local.pub"
+#define IKED_BTNSWILD	"pubkeys/fp/btns-wildcard"
 
 #define IKED_OPT_VERBOSE	0x00000001
 #define IKED_OPT_NOACTION	0x00000002
@@ -84,6 +86,7 @@
 	IMSG_CTL_NOTIFY,
 	IMSG_CTL_RELOAD,
 	IMSG_CTL_RESET,
+	IMSG_CTL_REQTYPE,
 	IMSG_CTL_COUPLE,
 	IMSG_CTL_DECOUPLE,
 	IMSG_CTL_ACTIVE,
@@ -98,6 +101,7 @@
 	IMSG_CERT,
 	IMSG_CERTVALID,
 	IMSG_CERTINVALID,
+	IMSG_CERTNOTFOUND,
 	IMSG_AUTH
 };
 
