Beispiel #1
0
/* Release a reference to SA.  */
void
sa_release(struct sa *sa)
{
	struct cert_handler *handler;
	struct proto   *proto;

	LOG_DBG((LOG_SA, 80, "sa_release: SA %p had %d references",
	    sa, sa->refcnt));

	if (--sa->refcnt)
		return;

	LOG_DBG((LOG_SA, 60, "sa_release: freeing SA %p", sa));

	while ((proto = TAILQ_FIRST(&sa->protos)) != 0)
		proto_free(proto);
	if (sa->data) {
		if (sa->doi && sa->doi->free_sa_data)
			sa->doi->free_sa_data(sa->data);
		free(sa->data);
	}
	free(sa->id_i);
	free(sa->id_r);
	if (sa->recv_cert) {
		handler = cert_get(sa->recv_certtype);
		if (handler)
			handler->cert_free(sa->recv_cert);
	}
	if (sa->sent_cert) {
		handler = cert_get(sa->sent_certtype);
		if (handler)
			handler->cert_free(sa->sent_cert);
	}
	if (sa->recv_key)
		key_free(sa->recv_keytype, ISAKMP_KEYTYPE_PUBLIC,
		    sa->recv_key);
	free(sa->keynote_key);	/* This is just a string */
	if (sa->policy_id != -1)
		kn_close(sa->policy_id);
	free(sa->name);
	free(sa->keystate);
	if (sa->nat_t_keepalive)
		timer_remove_event(sa->nat_t_keepalive);
	if (sa->dpd_event)
		timer_remove_event(sa->dpd_event);
	if (sa->transport)
		transport_release(sa->transport);
	free(sa->tag);
	free(sa);
}
Beispiel #2
0
/*
 * Decode the certificate request of type TYPE contained in DATA extending
 * DATALEN bytes.  Return a certreq_aca structure which the caller is
 * responsible for deallocating.
 */
struct certreq_aca *
certreq_decode(u_int16_t type, u_int8_t *data, u_int32_t datalen)
{
	struct cert_handler *handler;
	struct certreq_aca aca, *ret;

	handler = cert_get(type);
	if (!handler)
		return 0;

	aca.id = type;
	aca.handler = handler;
	aca.data = aca.raw_ca = NULL;

	if (datalen > 0) {
		int rc;

		rc = handler->certreq_decode(&aca.data, data, datalen);
		if (!rc)
			return 0;

		aca.raw_ca = malloc(datalen);
		if (aca.raw_ca == NULL) {
			log_error("certreq_decode: malloc (%lu) failed",
			    (unsigned long)datalen);
			handler->free_aca(aca.data);
			return 0;
		}

		memcpy(aca.raw_ca, data, datalen);
	}
	aca.raw_ca_len = datalen;

	ret = malloc(sizeof aca);
	if (!ret) {
		log_error("certreq_decode: malloc (%lu) failed",
		    (unsigned long)sizeof aca);
		free(aca.raw_ca);
		handler->free_aca(aca.data);
		return 0;
	}
	memcpy(ret, &aca, sizeof aca);
	return ret;
}
Beispiel #3
0
/* Encrypt the HASH into a SIG type.  */
static int
rsa_sig_encode_hash (struct message *msg)
{
  struct exchange *exchange = msg->exchange;
  struct ipsec_exch *ie = exchange->data;
  size_t hashsize = ie->hash->hashsize;
  struct cert_handler *handler;
  char header[80];
  int initiator = exchange->initiator;
  u_int8_t *buf, *data, *buf2;
  u_int32_t datalen;
  u_int8_t *id;
  size_t id_len;
  int idtype;
  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 || datalen == -1)
	{
	  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;
	}
#if defined (USE_PRIVSEP)
      {
	/* With USE_PRIVSEP, the sent_key should be a key number. */
	void *key = sent_key;
	sent_key = monitor_RSA_upload_key (key);
      }
#endif
    }
  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;
	}

#if defined (USE_PRIVSEP)
      sent_key = monitor_RSA_get_private_key (exchange->name, (char *)buf2);
#else
      sent_key = ike_auth_get_key (IKE_AUTH_RSA_SIG, exchange->name,
				   (char *)buf2, 0);
#endif
      free (buf2);

      /* Did we find a key?  */
      if (!sent_key)
	{
	  log_print ("rsa_sig_encode_hash: could not get private key");
	  return -1;
	}
    }

#if !defined (USE_PRIVSEP)
  /* Enable RSA blinding.  */
  if (RSA_blinding_on (sent_key, NULL) != 1)
    {
      log_error ("rsa_sig_encode_hash: RSA_blinding_on () failed.");
      return -1;
    }
#endif

  /* 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));

#if !defined (USE_PRIVSEP)
  data = malloc (RSA_size (sent_key));
  if (!data)
    {
      log_error ("rsa_sig_encode_hash: malloc (%d) failed",
		 RSA_size (sent_key));
      return -1;
    }

  datalen = RSA_private_encrypt (hashsize, buf, data, sent_key,
				 RSA_PKCS1_PADDING);
#else
  datalen = monitor_RSA_private_encrypt (hashsize, buf, &data, sent_key,
					 RSA_PKCS1_PADDING);
#endif /* USE_PRIVSEP */
  if (datalen == -1)
    {
      log_print ("rsa_sig_encode_hash: RSA_private_encrypt () failed");
      if (data)
	free (data);
      free (buf);
      monitor_RSA_free (sent_key);
      return -1;
    }

  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;
}
Beispiel #4
0
/* Decrypt the HASH in SIG, we already need a parsed ID payload.  */
static int
rsa_sig_decode_hash (struct message *msg)
{
  struct cert_handler *handler;
  struct exchange *exchange = msg->exchange;
  struct ipsec_exch *ie = exchange->data;
  struct payload *p;
  void *cert = 0;
  u_int8_t *rawcert = 0;
  u_int32_t rawcertlen;
  RSA *key = 0;
  size_t hashsize = ie->hash->hashsize;
  char header[80];
  int len;
  int initiator = exchange->initiator;
  u_int8_t **hash_p, **id_cert, *id;
  u_int32_t *id_cert_len;
  size_t id_len;
  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 = TAILQ_FIRST (&msg->payload[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 = TAILQ_FIRST (&msg->payload[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 = TAILQ_FIRST (&msg->payload[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 != 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;
}