Esempio n. 1
0
void
keynote_keygen(int argc, char *argv[])
{
    int begin = KEY_PRINT_OFFSET, prlen = KEY_PRINT_LENGTH;
    char *foo, *privalgname, seed[SEED_LEN];
    int alg, enc, ienc, len = 0, counter;
    struct keynote_deckey dc;
    unsigned long h;
    DSA *dsa;
    RSA *rsa;
    FILE *fp;
    char *algname;

    if ((argc != 5) && (argc != 6) && (argc != 7))
    {
	keygenusage();
	exit(0);
    }

    /* Fix algorithm name */
    if (argv[1][strlen(argv[1]) - 1] != ':')
    {
	int len = strlen(argv[1]) + 2;

        fprintf(stderr, "Algorithm name [%s] should be terminated with a "
		"colon, fixing.\n", argv[1]);
	algname = (char *) calloc(len, sizeof(char));
	if (algname == (char *) NULL)
	{
	    perror("calloc()");
	    exit(1);
	}

	strlcpy(algname, argv[1], len);
	algname[strlen(algname)] = ':';
    }
    else
	algname = argv[1];

    if (argc > 5)
    {
	begin = atoi(argv[5]);
	if (begin <= -1)
	{
	    fprintf(stderr, "Erroneous value for print-offset parameter.\n");
	    exit(1);
	}
    }

    if (argc > 6)
    {
	prlen = atoi(argv[6]);
	if (prlen <= 0)
	{
	    fprintf(stderr, "Erroneous value for print-length parameter.\n");
	    exit(1);
	}
    }

    if (strlen(algname) + 2 > prlen)
    {
	fprintf(stderr, "Parameter ``print-length'' should be larger "
		"than the length of AlgorithmName (%lu)\n",
		(unsigned long) strlen(algname));
	exit(1);
    }

    alg = keynote_get_key_algorithm(algname, &enc, &ienc);
    len = atoi(argv[2]);

    if (len <= 0)
    {
	fprintf(stderr, "Invalid specified keysize %d\n", len);
	exit(1);
    }

    if ((alg == KEYNOTE_ALGORITHM_DSA) &&
	(ienc == INTERNAL_ENC_ASN1) &&
	((enc == ENCODING_HEX) || (enc == ENCODING_BASE64)))
    {
        RAND_bytes(seed, SEED_LEN);

	dsa = DSA_generate_parameters(len, seed, SEED_LEN, &counter, &h, NULL
				      , NULL);

	if (dsa == (DSA *) NULL)
	{
	    ERR_print_errors_fp(stderr);
	    exit(1);
	}

	if (DSA_generate_key(dsa) != 1)
	{
	    ERR_print_errors_fp(stderr);
	    exit(1);
	}

	dc.dec_algorithm = KEYNOTE_ALGORITHM_DSA;
	dc.dec_key = (void *) dsa;

	foo = kn_encode_key(&dc, ienc, enc, KEYNOTE_PUBLIC_KEY);
	if (foo == (char *) NULL)
	{
	    fprintf(stderr, "Error encoding key (errno %d)\n", keynote_errno);
	    exit(1);
	}

	if (!strcmp(argv[3], "-"))
	  fp = stdout;
	else
	{
	    fp = fopen(argv[3], "w");
	    if (fp == (FILE *) NULL)
	    {
		perror(argv[3]);
		exit(1);
	    }
	}

	print_key(fp, algname, foo, begin, prlen);
	free(foo);

	if (strcmp(argv[3], "-"))
	  fclose(fp);

	foo = kn_encode_key(&dc, ienc, enc, KEYNOTE_PRIVATE_KEY);
	if (foo == (char *) NULL)
	{
	    fprintf(stderr, "Error encoding key (errno %d)\n", keynote_errno);
	    exit(1);
	}

	if (!strcmp(argv[4], "-"))
	{
	    fp = stdout;
	    if (!strcmp(argv[3], "-"))
	      printf("===========================\n");
	}
	else
	{
	    fp = fopen(argv[4], "w");
	    if (fp == (FILE *) NULL)
	    {
		perror(argv[4]);
		exit(1);
	    }
	}

	len = strlen(KEYNOTE_PRIVATE_KEY_PREFIX) + strlen(foo) + 1;
	privalgname = (char *) calloc(len, sizeof(char));
	if (privalgname == (char *) NULL)
	{
	    perror("calloc()");
	    exit(1);
	}
	snprintf(privalgname, len, "%s%s", KEYNOTE_PRIVATE_KEY_PREFIX, algname);
	print_key(fp, privalgname, foo, begin, prlen);
	free(privalgname);
	free(foo);

	if (strcmp(argv[4], "-"))
	  fclose(fp);

	exit(0);
    }

    if ((alg == KEYNOTE_ALGORITHM_RSA) &&
	(ienc == INTERNAL_ENC_PKCS1) &&
	((enc == ENCODING_HEX) || (enc == ENCODING_BASE64)))
    {
	rsa = RSA_generate_key(len, DEFAULT_PUBLIC, NULL, NULL);

	if (rsa == (RSA *) NULL)
	{
	    ERR_print_errors_fp(stderr);
	    exit(1);
	}

	dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
	dc.dec_key = (void *) rsa;

	foo = kn_encode_key(&dc, ienc, enc, KEYNOTE_PUBLIC_KEY);
	if (foo == (char *) NULL)
	{
	    fprintf(stderr, "Error encoding key (errno %d)\n", keynote_errno);
	    exit(1);
	}

	if (!strcmp(argv[3], "-"))
	  fp = stdout;
	else
	{
	    fp = fopen(argv[3], "w");
	    if (fp == (FILE *) NULL)
	    {
		perror(argv[3]);
		exit(1);
	    }
	}

	print_key(fp, algname, foo, begin, prlen);
	free(foo);

	if (strcmp(argv[3], "-"))
	  fclose(fp);

	foo = kn_encode_key(&dc, ienc, enc, KEYNOTE_PRIVATE_KEY);
	if (foo == (char *) NULL)
	{
	    fprintf(stderr, "Error encoding key (errno %d)\n", keynote_errno);
	    exit(1);
	}

	if (!strcmp(argv[4], "-"))
	{
	    fp = stdout;
	    if (!strcmp(argv[3], "-"))
	      printf("===========================\n");
	}
	else
	{
	    fp = fopen(argv[4], "w");
	    if (fp == (FILE *) NULL)
	    {
		perror(argv[4]);
		exit(1);
	    }
	}

	len = strlen(KEYNOTE_PRIVATE_KEY_PREFIX) + strlen(foo) + 1;
	privalgname = (char *) calloc(len, sizeof(char));
	if (privalgname == (char *) NULL)
	{
	    perror("calloc()");
	    exit(1);
	}
	snprintf(privalgname, len, "%s%s", KEYNOTE_PRIVATE_KEY_PREFIX, algname);
	print_key(fp, privalgname, foo, begin, prlen);
	free(privalgname);
	free(foo);

	if (strcmp(argv[4], "-"))
	  fclose(fp);

	exit(0);
    }

    /* More algorithms here */

    fprintf(stderr, "Unknown/unsupported algorithm [%s]\n", algname);
    exit(1);
}
Esempio n. 2
0
/*
 * Given an X509 certificate, create a KeyNote assertion where
 * Issuer/Subject -> Authorizer/Licensees.
 * XXX RSA-specific.
 */
int
x509_generate_kn(int id, X509 *cert)
{
	static const char fmt[] = "Authorizer: \"rsa-hex:%s\"\nLicensees: \"rsa-hex:%s"
		    "\"\nConditions: %s >= \"%s\" && %s <= \"%s\";\n";
	char	*ikey = NULL, *skey = NULL, *buf = NULL;
	char	isname[256], subname[256];
	static const char fmt2[] = "Authorizer: \"DN:%s\"\nLicensees: \"DN:%s\"\n"
		    "Conditions: %s >= \"%s\" && %s <= \"%s\";\n";
	X509_NAME *issuer, *subject;
	struct keynote_deckey dc;
	X509_STORE_CTX csc;
	X509_OBJECT obj;
	X509	*icert;
	RSA	*key = NULL;
	time_t	tt;
	char	before[15], after[15], *timecomp, *timecomp2;
	ASN1_TIME *tm;
	int	i;

	LOG_DBG((LOG_POLICY, 90,
	    "x509_generate_kn: generating KeyNote policy for certificate %p",
	    cert));

	issuer = X509_get_issuer_name(cert);
	subject = X509_get_subject_name(cert);

	/* Missing or self-signed, ignore cert but don't report failure.  */
	if (!issuer || !subject || !X509_name_cmp(issuer, subject))
		return 1;

	if (!x509_cert_get_key(cert, &key)) {
		LOG_DBG((LOG_POLICY, 30,
		    "x509_generate_kn: failed to get public key from cert"));
		return 0;
	}
	dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
	dc.dec_key = key;
	ikey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX,
	    KEYNOTE_PUBLIC_KEY);
	if (keynote_errno == ERROR_MEMORY) {
		log_print("x509_generate_kn: failed to get memory for "
		    "public key");
		LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get "
		    "subject key"));
		goto fail;
	}
	if (!ikey) {
		LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get "
		    "subject key"));
		goto fail;
	}

	RSA_free(key);
	key = NULL;

	/* Now find issuer's certificate so we can get the public key.  */
	X509_STORE_CTX_init(&csc, x509_cas, cert, NULL);
	if (X509_STORE_get_by_subject(&csc, X509_LU_X509, issuer, &obj) !=
	    X509_LU_X509) {
		X509_STORE_CTX_cleanup(&csc);
		X509_STORE_CTX_init(&csc, x509_certs, cert, NULL);
		if (X509_STORE_get_by_subject(&csc, X509_LU_X509, issuer, &obj)
		    != X509_LU_X509) {
			X509_STORE_CTX_cleanup(&csc);
			LOG_DBG((LOG_POLICY, 30,
			    "x509_generate_kn: no certificate found for "
			    "issuer"));
			goto fail;
		}
	}
	X509_STORE_CTX_cleanup(&csc);
	icert = obj.data.x509;

	if (icert == NULL) {
		LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: "
		    "missing certificates, cannot construct X509 chain"));
		goto fail;
	}
	if (!x509_cert_get_key(icert, &key)) {
		LOG_DBG((LOG_POLICY, 30,
		    "x509_generate_kn: failed to get public key from cert"));
		goto fail;
	}
	X509_OBJECT_free_contents(&obj);

	dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA;
	dc.dec_key = key;
	skey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX,
	    KEYNOTE_PUBLIC_KEY);
	if (keynote_errno == ERROR_MEMORY) {
		log_error("x509_generate_kn: failed to get memory for public "
		    "key");
		LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "
		    "key"));
		goto fail;
	}
	if (!skey) {
		LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer "
		    "key"));
		goto fail;
	}

	RSA_free(key);
	key = NULL;

	if (((tm = X509_get_notBefore(cert)) == NULL) ||
	    (tm->type != V_ASN1_UTCTIME &&
		tm->type != V_ASN1_GENERALIZEDTIME)) {
		tt = time(0);
		strftime(before, 14, "%Y%m%d%H%M%S", localtime(&tt));
		timecomp = "LocalTimeOfDay";
	} else {
		if (tm->data[tm->length - 1] == 'Z') {
			timecomp = "GMTTimeOfDay";
			i = tm->length - 2;
		} else {
			timecomp = "LocalTimeOfDay";
			i = tm->length - 1;
		}

		for (; i >= 0; i--) {
			if (tm->data[i] < '0' || tm->data[i] > '9') {
				LOG_DBG((LOG_POLICY, 30,
				    "x509_generate_kn: invalid data in "
				    "NotValidBefore time field"));
				goto fail;
			}
		}

		if (tm->type == V_ASN1_UTCTIME) {
			if ((tm->length < 10) || (tm->length > 13)) {
				LOG_DBG((LOG_POLICY, 30,
				    "x509_generate_kn: invalid length "
				    "of NotValidBefore time field (%d)",
				    tm->length));
				goto fail;
			}
			/* Validity checks.  */
			if ((tm->data[2] != '0' && tm->data[2] != '1') ||
			    (tm->data[2] == '0' && tm->data[3] == '0') ||
			    (tm->data[2] == '1' && tm->data[3] > '2') ||
			    (tm->data[4] > '3') ||
			    (tm->data[4] == '0' && tm->data[5] == '0') ||
			    (tm->data[4] == '3' && tm->data[5] > '1') ||
			    (tm->data[6] > '2') ||
			    (tm->data[6] == '2' && tm->data[7] > '3') ||
			    (tm->data[8] > '5')) {
				LOG_DBG((LOG_POLICY, 30,
				    "x509_generate_kn: invalid value in "
				    "NotValidBefore time field"));
				goto fail;
			}
			/* Stupid UTC tricks.  */
			if (tm->data[0] < '5')
				snprintf(before, sizeof before, "20%s",
				    tm->data);
			else
				snprintf(before, sizeof before, "19%s",
				    tm->data);
		} else {	/* V_ASN1_GENERICTIME */
			if ((tm->length < 12) || (tm->length > 15)) {
				LOG_DBG((LOG_POLICY, 30,
				    "x509_generate_kn: invalid length of "
				    "NotValidBefore time field (%d)",
				    tm->length));
				goto fail;
			}
			/* Validity checks.  */
			if ((tm->data[4] != '0' && tm->data[4] != '1') ||
			    (tm->data[4] == '0' && tm->data[5] == '0') ||
			    (tm->data[4] == '1' && tm->data[5] > '2') ||
			    (tm->data[6] > '3') ||
			    (tm->data[6] == '0' && tm->data[7] == '0') ||
			    (tm->data[6] == '3' && tm->data[7] > '1') ||
			    (tm->data[8] > '2') ||
			    (tm->data[8] == '2' && tm->data[9] > '3') ||
			    (tm->data[10] > '5')) {
				LOG_DBG((LOG_POLICY, 30,
				    "x509_generate_kn: invalid value in "
				    "NotValidBefore time field"));
				goto fail;
			}
			snprintf(before, sizeof before, "%s", tm->data);
		}

		/* Fix missing seconds.  */
		if (tm->length < 12) {
			before[12] = '0';
			before[13] = '0';
		}
		/* This will overwrite trailing 'Z'.  */
		before[14] = '\0';
	}

	tm = X509_get_notAfter(cert);
	if (tm == NULL &&
	    (tm->type != V_ASN1_UTCTIME &&
		tm->type != V_ASN1_GENERALIZEDTIME)) {
		tt = time(0);
		strftime(after, 14, "%Y%m%d%H%M%S", localtime(&tt));
		timecomp2 = "LocalTimeOfDay";
	} else {
		if (tm->data[tm->length - 1] == 'Z') {
			timecomp2 = "GMTTimeOfDay";
			i = tm->length - 2;
		} else {
			timecomp2 = "LocalTimeOfDay";
			i = tm->length - 1;
		}

		for (; i >= 0; i--) {
			if (tm->data[i] < '0' || tm->data[i] > '9') {
				LOG_DBG((LOG_POLICY, 30,
				    "x509_generate_kn: invalid data in "
				    "NotValidAfter time field"));
				goto fail;
			}
		}

		if (tm->type == V_ASN1_UTCTIME) {
			if ((tm->length < 10) || (tm->length > 13)) {
				LOG_DBG((LOG_POLICY, 30,
				    "x509_generate_kn: invalid length of "
				    "NotValidAfter time field (%d)",
				    tm->length));
				goto fail;
			}
			/* Validity checks. */
			if ((tm->data[2] != '0' && tm->data[2] != '1') ||
			    (tm->data[2] == '0' && tm->data[3] == '0') ||
			    (tm->data[2] == '1' && tm->data[3] > '2') ||
			    (tm->data[4] > '3') ||
			    (tm->data[4] == '0' && tm->data[5] == '0') ||
			    (tm->data[4] == '3' && tm->data[5] > '1') ||
			    (tm->data[6] > '2') ||
			    (tm->data[6] == '2' && tm->data[7] > '3') ||
			    (tm->data[8] > '5')) {
				LOG_DBG((LOG_POLICY, 30,
				    "x509_generate_kn: invalid value in "
				    "NotValidAfter time field"));
				goto fail;
			}
			/* Stupid UTC tricks.  */
			if (tm->data[0] < '5')
				snprintf(after, sizeof after, "20%s",
				    tm->data);
			else
				snprintf(after, sizeof after, "19%s",
				    tm->data);
		} else {	/* V_ASN1_GENERICTIME */
			if ((tm->length < 12) || (tm->length > 15)) {
				LOG_DBG((LOG_POLICY, 30,
				    "x509_generate_kn: invalid length of "
				    "NotValidAfter time field (%d)",
				    tm->length));
				goto fail;
			}
			/* Validity checks.  */
			if ((tm->data[4] != '0' && tm->data[4] != '1') ||
			    (tm->data[4] == '0' && tm->data[5] == '0') ||
			    (tm->data[4] == '1' && tm->data[5] > '2') ||
			    (tm->data[6] > '3') ||
			    (tm->data[6] == '0' && tm->data[7] == '0') ||
			    (tm->data[6] == '3' && tm->data[7] > '1') ||
			    (tm->data[8] > '2') ||
			    (tm->data[8] == '2' && tm->data[9] > '3') ||
			    (tm->data[10] > '5')) {
				LOG_DBG((LOG_POLICY, 30,
				    "x509_generate_kn: invalid value in "
				    "NotValidAfter time field"));
				goto fail;
			}
			snprintf(after, sizeof after, "%s", tm->data);
		}

		/* Fix missing seconds.  */
		if (tm->length < 12) {
			after[12] = '0';
			after[13] = '0';
		}
		after[14] = '\0';	/* This will overwrite trailing 'Z' */
	}

	if (asprintf(&buf, fmt, skey, ikey, timecomp, before, timecomp2,
	    after) == -1) {
		log_error("x509_generate_kn: "
		    "failed to allocate memory for KeyNote credential");
		goto fail;
	}
	
	free(ikey);
	ikey = NULL;
	free(skey);
	skey = NULL;

	if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) {
		LOG_DBG((LOG_POLICY, 30,
		    "x509_generate_kn: failed to add new KeyNote credential"));
		goto fail;
	}
	/* We could print the assertion here, but log_print() truncates...  */
	LOG_DBG((LOG_POLICY, 60, "x509_generate_kn: added credential"));

	free(buf);
	buf = NULL;

	if (!X509_NAME_oneline(issuer, isname, 256)) {
		LOG_DBG((LOG_POLICY, 50,
		    "x509_generate_kn: "
		    "X509_NAME_oneline (issuer, ...) failed"));
		goto fail;
	}
	if (!X509_NAME_oneline(subject, subname, 256)) {
		LOG_DBG((LOG_POLICY, 50,
		    "x509_generate_kn: "
		    "X509_NAME_oneline (subject, ...) failed"));
		goto fail;
	}
	if (asprintf(&buf, fmt2, isname, subname, timecomp, before,
	    timecomp2, after) == -1) {
		log_error("x509_generate_kn: malloc failed");
		return 0;
	}

	if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) {
		LOG_DBG((LOG_POLICY, 30,
		    "x509_generate_kn: failed to add new KeyNote credential"));
		goto fail;
	}
	LOG_DBG((LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s",
	    buf));

	free(buf);
	return 1;

fail:
	free(buf);
	free(skey);
	free(ikey);
	if (key)
		RSA_free(key);

	return 0;
}
Esempio n. 3
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;
}