Ejemplo n.º 1
0
SilcBool silc_pkcs1_verify_no_oid(void *public_key,
				  unsigned char *signature,
				  SilcUInt32 signature_len,
				  unsigned char *data,
				  SilcUInt32 data_len,
				  SilcHash hash)
{
  RsaPublicKey *key = public_key;
  SilcBool ret = FALSE;
  SilcMPInt mp_tmp2;
  SilcMPInt mp_dst;
  unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN];
  SilcUInt32 verify_len, len = (key->bits + 7) / 8;

  SILC_LOG_DEBUG(("Verify signature"));

  silc_mp_init(&mp_tmp2);
  silc_mp_init(&mp_dst);

  /* Format the signature into MP int */
  silc_mp_bin2mp(signature, signature_len, &mp_tmp2);

  /* Verify */
  silc_rsa_public_operation(key, &mp_tmp2, &mp_dst);

  /* MP to data */
  verify = silc_mp_mp2bin(&mp_dst, len, &verify_len);

  /* Unpad data */
  if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len,
			 unpadded, sizeof(unpadded), &len)) {
    memset(verify, 0, verify_len);
    silc_free(verify);
    silc_mp_uninit(&mp_tmp2);
    silc_mp_uninit(&mp_dst);
    return FALSE;
  }

  /* Hash data if requested */
  if (hash) {
    silc_hash_make(hash, data, data_len, hashr);
    data = hashr;
    data_len = silc_hash_len(hash);
  }

  /* Compare */
  if (len == data_len && !memcmp(data, unpadded, len))
    ret = TRUE;

  memset(verify, 0, verify_len);
  memset(unpadded, 0, sizeof(unpadded));
  silc_free(verify);
  silc_mp_uninit(&mp_tmp2);
  silc_mp_uninit(&mp_dst);
  if (hash)
    memset(hashr, 0, sizeof(hashr));

  return ret;
}
Ejemplo n.º 2
0
SilcBool silc_pkcs1_sign_no_oid(void *private_key,
				unsigned char *src,
				SilcUInt32 src_len,
				unsigned char *signature,
				SilcUInt32 signature_size,
				SilcUInt32 *ret_signature_len,
				SilcBool compute_hash,
				SilcHash hash)
{
  RsaPrivateKey *key = private_key;
  SilcMPInt mp_tmp;
  SilcMPInt mp_dst;
  unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN];
  SilcUInt32 len = (key->bits + 7) / 8;

  SILC_LOG_DEBUG(("Sign"));

  if (sizeof(padded) < len)
    return FALSE;
  if (signature_size < len)
    return FALSE;

  /* Compute hash if requested */
  if (compute_hash) {
    silc_hash_make(hash, src, src_len, hashr);
    src = hashr;
    src_len = silc_hash_len(hash);
  }

  /* Pad data */
  if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, src, src_len,
			 padded, len, NULL))
    return FALSE;

  silc_mp_init(&mp_tmp);
  silc_mp_init(&mp_dst);

  /* Data to MP */
  silc_mp_bin2mp(padded, len, &mp_tmp);

  /* Sign */
  silc_rsa_private_operation(key, &mp_tmp, &mp_dst);

  /* MP to data */
  silc_mp_mp2bin_noalloc(&mp_dst, signature, len);
  *ret_signature_len = len;

  memset(padded, 0, sizeof(padded));
  silc_mp_uninit(&mp_tmp);
  silc_mp_uninit(&mp_dst);
  if (compute_hash)
    memset(hashr, 0, sizeof(hashr));

  return TRUE;
}
Ejemplo n.º 3
0
int silc_idlist_get_clients_by_hash(SilcIDList id_list,
				    char *nickname, char *server,
				    SilcHash md5hash,
				    SilcClientEntry **clients,
				    SilcUInt32 *clients_count)
{
  SilcList list;
  SilcIDCacheEntry id_cache = NULL;
  unsigned char hash[SILC_HASH_MAXLEN];
  SilcClientID client_id;
  SilcClientEntry client_entry;

  SILC_LOG_DEBUG(("Start"));

  silc_hash_make(md5hash, nickname, strlen(nickname), hash);

  /* As the Client ID is hashed in the ID cache by hashing only the hash
     from the Client ID, we can do a lookup with only the hash not the
     other parts of the ID and get all the clients with that hash, ie.
     with that nickname, as the hash is from the nickname. */
  memset(&client_id, 0, sizeof(client_id));
  memcpy(&client_id.hash, hash, sizeof(client_id.hash));
  if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
    return FALSE;

  /* If server is specified, narrow the search with it. */
  if (server) {
    silc_list_start(list);
    while ((id_cache = silc_list_get(list))) {
      client_entry = id_cache->context;
      if (!client_entry->servername)
	continue;
      if (!silc_utf8_strcasecmp(client_entry->servername, server))
	silc_list_del(list, id_cache);
    }
  }

  if (!silc_list_count(list))
    return FALSE;

  *clients = silc_realloc(*clients,
			  (silc_list_count(list) + *clients_count) *
			  sizeof(**clients));

  silc_list_start(list);
  while ((id_cache = silc_list_get(list)))
    (*clients)[(*clients_count)++] = id_cache->context;

  SILC_LOG_DEBUG(("Found total %d clients", *clients_count));

  return TRUE;
}
Ejemplo n.º 4
0
SilcBool silc_client_add_channel_private_key(SilcClient client,
					     SilcClientConnection conn,
					     SilcChannelEntry channel,
					     const char *name,
					     char *cipher,
					     char *hmac,
					     unsigned char *key,
					     SilcUInt32 key_len,
					     SilcChannelPrivateKey *ret_key)
{
  SilcChannelPrivateKey entry;
  unsigned char hash[SILC_HASH_MAXLEN];
  SilcSKEKeyMaterial keymat;

  if (!client || !conn || !channel)
    return FALSE;

  if (!cipher)
    cipher = SILC_DEFAULT_CIPHER;
  if (!hmac)
    hmac = SILC_DEFAULT_HMAC;

  if (!silc_cipher_is_supported(cipher))
    return FALSE;
  if (!silc_hmac_is_supported(hmac))
    return FALSE;

  if (!channel->internal.private_keys) {
    channel->internal.private_keys = silc_dlist_init();
    if (!channel->internal.private_keys)
      return FALSE;
  }

  /* Produce the key material */
  keymat = silc_ske_process_key_material_data(key, key_len, 16, 256, 16,
					      conn->internal->sha1hash);
  if (!keymat)
    return FALSE;

  /* Save the key */
  entry = silc_calloc(1, sizeof(*entry));
  if (!entry) {
    silc_ske_free_key_material(keymat);
    return FALSE;
  }
  entry->name = name ? strdup(name) : NULL;

  /* Allocate the cipher and set the key */
  if (!silc_cipher_alloc(cipher, &entry->send_key)) {
    silc_free(entry);
    silc_free(entry->name);
    silc_ske_free_key_material(keymat);
    return FALSE;
  }
  if (!silc_cipher_alloc(cipher, &entry->receive_key)) {
    silc_free(entry);
    silc_free(entry->name);
    silc_cipher_free(entry->send_key);
    silc_ske_free_key_material(keymat);
    return FALSE;
  }
  silc_cipher_set_key(entry->send_key, keymat->send_enc_key,
		      keymat->enc_key_len, TRUE);
  silc_cipher_set_key(entry->receive_key, keymat->send_enc_key,
		      keymat->enc_key_len, FALSE);

  /* Generate HMAC key from the channel key data and set it */
  if (!silc_hmac_alloc(hmac, NULL, &entry->hmac)) {
    silc_free(entry);
    silc_free(entry->name);
    silc_cipher_free(entry->send_key);
    silc_cipher_free(entry->receive_key);
    silc_ske_free_key_material(keymat);
    return FALSE;
  }
  silc_hash_make(silc_hmac_get_hash(entry->hmac), keymat->send_enc_key,
		 keymat->enc_key_len / 8, hash);
  silc_hmac_set_key(entry->hmac, hash,
		    silc_hash_len(silc_hmac_get_hash(entry->hmac)));
  memset(hash, 0, sizeof(hash));

  /* Add to the private keys list */
  silc_dlist_add(channel->internal.private_keys, entry);

  if (!channel->internal.curr_key) {
    channel->internal.curr_key = entry;
    channel->cipher = silc_cipher_get_name(entry->send_key);
    channel->hmac = silc_cipher_get_name(entry->send_key);
  }

  /* Free the key material */
  silc_ske_free_key_material(keymat);

  if (ret_key)
    *ret_key = entry;

  return TRUE;
}
Ejemplo n.º 5
0
SilcBool silc_client_save_channel_key(SilcClient client,
				      SilcClientConnection conn,
				      SilcBuffer key_payload,
				      SilcChannelEntry channel)
{
  unsigned char *id_string, *key, *cipher, *hmac, hash[SILC_HASH_MAXLEN];
  SilcUInt32 tmp_len;
  SilcChannelID id;
  SilcChannelKeyPayload payload;

  SILC_LOG_DEBUG(("New channel key"));

  payload = silc_channel_key_payload_parse(silc_buffer_data(key_payload),
					   silc_buffer_len(key_payload));
  if (!payload)
    return FALSE;

  id_string = silc_channel_key_get_id(payload, &tmp_len);
  if (!id_string) {
    silc_channel_key_payload_free(payload);
    return FALSE;
  }

  if (!silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL, &id, sizeof(id))) {
    silc_channel_key_payload_free(payload);
    return FALSE;
  }

  /* Find channel. */
  if (!channel) {
    channel = silc_client_get_channel_by_id(client, conn, &id);
    if (!channel) {
      SILC_LOG_DEBUG(("Key for unknown channel"));
      silc_channel_key_payload_free(payload);
      return FALSE;
    }
  } else {
    silc_client_ref_channel(client, conn, channel);
  }

  /* Save the old key for a short period of time so that we can decrypt
     channel message even after the rekey if some client would be sending
     messages with the old key after the rekey. */
  if (!channel->internal.old_channel_keys)
    channel->internal.old_channel_keys = silc_dlist_init();
  if (!channel->internal.old_hmacs)
    channel->internal.old_hmacs = silc_dlist_init();
  if (channel->internal.old_channel_keys && channel->internal.old_hmacs) {
    silc_dlist_add(channel->internal.old_channel_keys,
		   channel->internal.receive_key);
    silc_dlist_add(channel->internal.old_hmacs, channel->internal.hmac);
    silc_schedule_task_add_timeout(client->schedule,
				   silc_client_save_channel_key_rekey,
				   channel, 15, 0);
  }

  /* Get channel cipher */
  cipher = silc_channel_key_get_cipher(payload, NULL);
  if (!silc_cipher_alloc(cipher, &channel->internal.send_key)) {
    client->internal->ops->say(
			   conn->client, conn,
			   SILC_CLIENT_MESSAGE_AUDIT,
			   "Cannot talk to channel: unsupported cipher %s",
			   cipher);
    silc_client_unref_channel(client, conn, channel);
    silc_channel_key_payload_free(payload);
    return FALSE;
  }
  if (!silc_cipher_alloc(cipher, &channel->internal.receive_key)) {
    client->internal->ops->say(
			   conn->client, conn,
			   SILC_CLIENT_MESSAGE_AUDIT,
			   "Cannot talk to channel: unsupported cipher %s",
			   cipher);
    silc_client_unref_channel(client, conn, channel);
    silc_channel_key_payload_free(payload);
    return FALSE;
  }

  /* Set the cipher key.  Both sending and receiving keys are same */
  key = silc_channel_key_get_key(payload, &tmp_len);
  silc_cipher_set_key(channel->internal.send_key, key, tmp_len * 8, TRUE);
  silc_cipher_set_key(channel->internal.receive_key, key, tmp_len * 8, FALSE);

  /* Get channel HMAC */
  hmac = (channel->internal.hmac ?
	  (char *)silc_hmac_get_name(channel->internal.hmac) :
	  SILC_DEFAULT_HMAC);
  if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
    client->internal->ops->say(
			   conn->client, conn,
			   SILC_CLIENT_MESSAGE_AUDIT,
			   "Cannot talk to channel: unsupported HMAC %s",
			   hmac);
    silc_client_unref_channel(client, conn, channel);
    silc_channel_key_payload_free(payload);
    return FALSE;
  }

  channel->cipher = silc_cipher_get_name(channel->internal.send_key);
  channel->hmac = silc_hmac_get_name(channel->internal.hmac);

  /* Set HMAC key */
  silc_hash_make(silc_hmac_get_hash(channel->internal.hmac), key,
		 tmp_len, hash);
  silc_hmac_set_key(channel->internal.hmac, hash,
		    silc_hash_len(silc_hmac_get_hash(channel->internal.hmac)));
  memset(hash, 0, sizeof(hash));
  silc_channel_key_payload_free(payload);

  silc_client_unref_channel(client, conn, channel);

  return TRUE;
}
Ejemplo n.º 6
0
static char
silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
{
  SilcServer server = cmd->server;
  unsigned char *id_data, *umodes;
  char *nickname, *username, *realname, *tmp;
  unsigned char *fingerprint;
  SilcID id;
  SilcClientEntry client;
  char global = FALSE;
  char nick[128 + 1], servername[256 + 1], uname[128 + 1];
  SilcUInt32 mode = 0, len, len2, id_len, flen;
  const char *hostname, *ip;

  silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
			      NULL, &hostname, &ip, NULL);

  id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
  nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
  username = silc_argument_get_arg_type(cmd->args, 4, &len);
  realname = silc_argument_get_arg_type(cmd->args, 5, &len);
  if (!id_data || !nickname || !username || !realname)
    return FALSE;

  tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
  if (tmp)
    SILC_GET32_MSB(mode, tmp);

  if (!silc_id_payload_parse_id(id_data, id_len, &id))
    return FALSE;

  fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);

  /* Check if we have this client cached already. */

  client = silc_idlist_find_client_by_id(server->local_list,
					 SILC_ID_GET_ID(id),
					 FALSE, NULL);
  if (!client) {
    client = silc_idlist_find_client_by_id(server->global_list,
					   SILC_ID_GET_ID(id),
					   FALSE, NULL);
    global = TRUE;
  }

  if (!client) {
    /* If router did not find such Client ID in its lists then this must
       be bogus client or some router in the net is buggy. */
    if (server->server_type != SILC_SERVER)
      return FALSE;

    /* Take hostname out of nick string if it includes it. */
    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
			sizeof(servername));

    /* We don't have that client anywhere, add it. The client is added
       to global list since server didn't have it in the lists so it must be
       global. This will check for valid nickname and username strings. */
    client = silc_idlist_add_client(server->global_list,
				    strdup(nick), username,
				    strdup(realname),
				    silc_id_dup(SILC_ID_GET_ID(id),
						SILC_ID_CLIENT),
				    silc_packet_get_context(cmd->sock),
				    NULL);
    if (!client) {
      SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
      return FALSE;
    }

    client->data.status |=
      (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
    client->mode = mode;
    client->servername = servername[0] ? strdup(servername) : NULL;

    SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
		    server->stat.clients + 1));
    server->stat.clients++;
  } else {
    /* We have the client already, update the data */

    SILC_LOG_DEBUG(("Updating client data"));

    /* Check nickname */
    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
			sizeof(servername));
    nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
				     128, NULL);
    if (!nickname) {
      SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOIS reply "
		      "from %s",
		      hostname ? hostname : "", nick));
      return FALSE;
    }

    /* Check username */
    silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0);
    if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128)) {
      SILC_LOG_ERROR(("Malformed username '%s' received in WHOIS reply "
		      "from %s",
		      hostname ? hostname : "", tmp));
      return FALSE;
    }

    /* Update entry */
    silc_idcache_update_by_context(global ? server->global_list->clients :
				   server->local_list->clients, client, NULL,
				   nickname, TRUE);

    silc_free(client->nickname);
    silc_free(client->username);
    silc_free(client->userinfo);
    silc_free(client->servername);

    client->nickname = strdup(nick);
    client->username = strdup(username);
    client->userinfo = strdup(realname);
    client->servername = servername[0] ? strdup(servername) : NULL;
    client->mode = mode;
    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
  }

  /* Save channel list if it was sent to us */
  if (server->server_type == SILC_SERVER) {
    tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
    umodes = silc_argument_get_arg_type(cmd->args, 10, &len2);
    if (tmp && umodes) {
      SilcBufferStruct channels_buf, umodes_buf;
      silc_buffer_set(&channels_buf, tmp, len);
      silc_buffer_set(&umodes_buf, umodes, len2);
      silc_server_save_user_channels(server, cmd->sock, client, &channels_buf,
				     &umodes_buf);
    } else {
      silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
    }
  }

  if (fingerprint && flen == sizeof(client->data.fingerprint))
    memcpy(client->data.fingerprint, fingerprint, flen);

  /* Take Requested Attributes if set. */
  tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
  if (tmp) {
    silc_free(client->attrs);
    client->attrs = silc_memdup(tmp, len);
    client->attrs_len = len;

    /* Try to take public key from attributes if present and we don't have
       the key already.  Do this only on normal server.  Routers do GETKEY
       for all clients anyway. */
    if (server->server_type != SILC_ROUTER && !client->data.public_key) {
      SilcAttributePayload attr;
      SilcAttributeObjPk pk;
      unsigned char f[SILC_HASH_MAXLEN];
      SilcDList attrs = silc_attribute_payload_parse(tmp, len);

      SILC_LOG_DEBUG(("Take client public key from attributes"));

      if (attrs) {
	silc_dlist_start(attrs);
	while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
	  if (silc_attribute_get_attribute(attr) ==
	      SILC_ATTRIBUTE_USER_PUBLIC_KEY) {

	    if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
	      continue;

	    /* Take only SILC public keys */
	    if (strcmp(pk.type, "silc-rsa")) {
	      silc_free(pk.type);
	      silc_free(pk.data);
	      continue;
	    }

	    /* Verify that the server provided fingerprint matches the key */
	    silc_hash_make(server->sha1hash, pk.data, pk.data_len, f);
	    if (memcmp(f, client->data.fingerprint, sizeof(f))) {
	      silc_free(pk.type);
	      silc_free(pk.data);
	      continue;
	    }

	    /* Save the public key. */
	    if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC,
					    pk.data, pk.data_len,
					    &client->data.public_key)) {
	      silc_free(pk.type);
	      silc_free(pk.data);
	      continue;
	    }

	    SILC_LOG_DEBUG(("Saved client public key from attributes"));

	    /* Add client's public key to repository */
	    if (!silc_server_get_public_key_by_client(server, client, NULL))
	      silc_skr_add_public_key_simple(server->repository,
					     client->data.public_key,
					     SILC_SKR_USAGE_IDENTIFICATION,
					     client, NULL);

	    silc_free(pk.type);
	    silc_free(pk.data);
	    break;
	  }
	}

	silc_attribute_payload_list_free(attrs);
      }
    }
  }

  return TRUE;
}
Ejemplo n.º 7
0
SilcBool silc_pkcs1_verify(void *public_key,
			   unsigned char *signature,
			   SilcUInt32 signature_len,
			   unsigned char *data,
			   SilcUInt32 data_len,
			   SilcHash hash)
{
  RsaPublicKey *key = public_key;
  SilcBool ret = FALSE;
  SilcMPInt mp_tmp2;
  SilcMPInt mp_dst;
  unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN];
  SilcUInt32 verify_len, len = (key->bits + 7) / 8;
  SilcBufferStruct di, ldi;
  SilcHash ihash = NULL;
  SilcAsn1 asn1 = NULL;
  char *oid;

  SILC_LOG_DEBUG(("Verify signature"));

  asn1 = silc_asn1_alloc();
  if (!asn1)
    return FALSE;

  silc_mp_init(&mp_tmp2);
  silc_mp_init(&mp_dst);

  /* Format the signature into MP int */
  silc_mp_bin2mp(signature, signature_len, &mp_tmp2);

  /* Verify */
  silc_rsa_public_operation(key, &mp_tmp2, &mp_dst);

  /* MP to data */
  verify = silc_mp_mp2bin(&mp_dst, len, &verify_len);

  /* Unpad data */
  if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len,
			 unpadded, sizeof(unpadded), &len))
    goto err;
  silc_buffer_set(&di, unpadded, len);

  /* If hash isn't given, allocate the one given in digest info */
  if (!hash) {
    /* Decode digest info */
    if (!silc_asn1_decode(asn1, &di,
			  SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
			  SILC_ASN1_SEQUENCE,
			    SILC_ASN1_SEQUENCE,
			      SILC_ASN1_OID(&oid),
			    SILC_ASN1_END,
			  SILC_ASN1_END, SILC_ASN1_END))
      goto err;

    if (!silc_hash_alloc_by_oid(oid, &ihash)) {
      SILC_LOG_DEBUG(("Unknown OID %s", oid));
      goto err;
    }
    hash = ihash;
  }

  /* Hash the data */
  silc_hash_make(hash, data, data_len, hashr);
  data = hashr;
  data_len = silc_hash_len(hash);
  oid = (char *)silc_hash_get_oid(hash);

  /* Encode digest info for comparison */
  memset(&ldi, 0, sizeof(ldi));
  if (!silc_asn1_encode(asn1, &ldi,
			SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
			SILC_ASN1_SEQUENCE,
			  SILC_ASN1_SEQUENCE,
			    SILC_ASN1_OID(oid),
			    SILC_ASN1_NULL,
			  SILC_ASN1_END,
			  SILC_ASN1_OCTET_STRING(data, data_len),
			SILC_ASN1_END, SILC_ASN1_END))
    goto err;

  SILC_LOG_HEXDUMP(("DigestInfo remote"), silc_buffer_data(&di),
		   silc_buffer_len(&di));
  SILC_LOG_HEXDUMP(("DigestInfo local"), silc_buffer_data(&ldi),
		   silc_buffer_len(&ldi));

  /* Compare */
  if (silc_buffer_len(&di) == silc_buffer_len(&ldi) &&
      !memcmp(silc_buffer_data(&di), silc_buffer_data(&ldi),
	      silc_buffer_len(&ldi)))
    ret = TRUE;

  memset(verify, 0, verify_len);
  memset(unpadded, 0, sizeof(unpadded));
  silc_free(verify);
  silc_mp_uninit(&mp_tmp2);
  silc_mp_uninit(&mp_dst);
  if (hash)
    memset(hashr, 0, sizeof(hashr));
  if (ihash)
    silc_hash_free(ihash);
  silc_asn1_free(asn1);

  return ret;

 err:
  memset(verify, 0, verify_len);
  silc_free(verify);
  silc_mp_uninit(&mp_tmp2);
  silc_mp_uninit(&mp_dst);
  if (ihash)
    silc_hash_free(ihash);
  silc_asn1_free(asn1);
  return FALSE;
}
Ejemplo n.º 8
0
SilcBool silc_pkcs1_sign(void *private_key,
			 unsigned char *src,
			 SilcUInt32 src_len,
			 unsigned char *signature,
			 SilcUInt32 signature_size,
			 SilcUInt32 *ret_signature_len,
			 SilcBool compute_hash,
			 SilcHash hash)
{
  RsaPrivateKey *key = private_key;
  unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN];
  SilcMPInt mp_tmp;
  SilcMPInt mp_dst;
  SilcBufferStruct di;
  SilcUInt32 len = (key->bits + 7) / 8;
  const char *oid;
  SilcAsn1 asn1;

  SILC_LOG_DEBUG(("Sign"));

  if (sizeof(padded) < len)
    return FALSE;
  if (signature_size < len)
    return FALSE;

  oid = silc_hash_get_oid(hash);
  if (!oid)
    return FALSE;

  asn1 = silc_asn1_alloc();
  if (!asn1)
    return FALSE;

  /* Compute hash */
  if (compute_hash) {
    silc_hash_make(hash, src, src_len, hashr);
    src = hashr;
    src_len = silc_hash_len(hash);
  }

  /* Encode digest info */
  memset(&di, 0, sizeof(di));
  if (!silc_asn1_encode(asn1, &di,
			SILC_ASN1_SEQUENCE,
			  SILC_ASN1_SEQUENCE,
			    SILC_ASN1_OID(oid),
			    SILC_ASN1_NULL,
			  SILC_ASN1_END,
			  SILC_ASN1_OCTET_STRING(src, src_len),
			SILC_ASN1_END, SILC_ASN1_END)) {
    silc_asn1_free(asn1);
    return FALSE;
  }
  SILC_LOG_HEXDUMP(("DigestInfo"), silc_buffer_data(&di),
		   silc_buffer_len(&di));

  /* Pad data */
  if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, silc_buffer_data(&di),
			 silc_buffer_len(&di), padded, len, NULL)) {
    silc_asn1_free(asn1);
    return FALSE;
  }

  silc_mp_init(&mp_tmp);
  silc_mp_init(&mp_dst);

  /* Data to MP */
  silc_mp_bin2mp(padded, len, &mp_tmp);

  /* Sign */
  silc_rsa_private_operation(key, &mp_tmp, &mp_dst);

  /* MP to data */
  silc_mp_mp2bin_noalloc(&mp_dst, signature, len);
  *ret_signature_len = len;

  memset(padded, 0, sizeof(padded));
  silc_mp_uninit(&mp_tmp);
  silc_mp_uninit(&mp_dst);
  if (compute_hash)
    memset(hashr, 0, sizeof(hashr));
  silc_asn1_free(asn1);

  return TRUE;
}