/** * <summary>Disk caching is unsupported at this time.</summary> */ /* When we have a cache eviction, we must write it to disk, we take * each entry, convert it explicitly into a hashtable, and then use adr * to create a stream and write it to disk */ public void CacheEviction(Object o, EventArgs args) { Brunet.Collections.Cache.EvictionArgs eargs = (Brunet.Collections.Cache.EvictionArgs)args; MemBlock key = (MemBlock)eargs.Key; if (Dht.DhtLog.Enabled) { ProtocolLog.Write(Dht.DhtLog, String.Format( "Evicted out of cache {0}, entries in dht {1}, entries in cache {2}", (new BigInteger(key)).ToString(16), Count, _data.Count)); } if (eargs.Value != null && ((LinkedList <Entry>)eargs.Value).Count > 0) { LinkedList <Entry> data = (LinkedList <Entry>)eargs.Value; // AdrConverter doesn't support LinkedLists Entry[] entries = new Entry[data.Count]; data.CopyTo(entries, 0); Hashtable[] ht_entries = new Hashtable[entries.Length]; int index = 0; foreach (Entry entry in entries) { ht_entries[index++] = (Hashtable)entry; } string dir_path, filename; string file_path = GeneratePath(key, out dir_path, out filename); if (!Directory.Exists(dir_path)) { Directory.CreateDirectory(dir_path); } using (FileStream fs = File.Open(file_path, FileMode.Create)) { AdrConverter.Serialize(ht_entries, fs); } } }
/// <summary>Parse a revocation message.</summary> public UserRevocationMessage(Certificate cacert, MemBlock data) { _data = data; int pos = 0; int length = 0; Username = AdrConverter.Deserialize(data, pos, out length) as string; pos += length; // Random number to reduce likelihood of malicious duplication of messages NumberSerializer.ReadInt(data, pos); pos += 4; // Verify that there is a date contained therein, perhaps we should verify the time new DateTime(NumberSerializer.ReadLong(data, pos)); pos += 8; Signature = new byte[data.Length - pos]; data.Slice(pos).CopyTo(Signature, 0); // hash the data SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); Hash = sha1.ComputeHash(data, 0, data.Length - Signature.Length); if (!cacert.PublicKey.VerifyHash(Hash, CryptoConfig.MapNameToOID("SHA1"), Signature)) { throw new Exception("Invalid UserRevocationMessage signature"); } }
protected void SendControlPacket(EndPoint end, int remoteid, int localid, ControlCode c, object state) { using (MemoryStream ms = new MemoryStream()) { NumberSerializer.WriteInt((int)c, ms); if (c == ControlCode.EdgeDataAnnounce) { UdpEdge e = (UdpEdge)_id_ht[localid]; if ((e != null) && (e.RemoteID == remoteid)) { Hashtable t = new Hashtable(); t["RemoteTA"] = e.RemoteTA.ToString(); t["LocalTA"] = e.LocalTA.ToString(); AdrConverter.Serialize(t, ms); } else { if (ProtocolLog.UdpEdge.Enabled) { ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format( "Problem sending EdgeData: EndPoint: {0}, remoteid: {1}, " + "localid: {2}, Edge: {3}", end, remoteid, localid, e)); } } } _send_queue.Enqueue(new UdpMessage(localid, ~remoteid, MemBlock.Reference(ms.ToArray()), end)); if (ProtocolLog.UdpEdge.Enabled) { ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format( "Sending control {1} to: {0}", end, c)); } } }
/** * Implements the IReplyHandler (also provides some light-weight statistics) */ public bool HandleReply(ReqrepManager man, ReqrepManager.ReqrepType rt, int mid, PType prot, MemBlock payload, ISender ret_path, ReqrepManager.Statistics statistics, object state) { RpcRequestState rs = (RpcRequestState)state; //ISender target = rs.RpcTarget; Channel bq = rs.Results; if (bq != null) { object data = AdrConverter.Deserialize(payload); RpcResult res = new RpcResult(ret_path, data, statistics); //handle possible exception: try { bq.Enqueue(res); //Keep listening unless the queue is closed return(!bq.Closed); } catch (System.InvalidOperationException) { //The queue is closed, stop listening for more results: return(false); } } else { //If they didn't even pass us a queue, I guess they didn't want to //listen too long return(false); } }
public byte[] Serialize(object o) { using (MemoryStream ms = new MemoryStream()) { AdrConverter.Serialize(o, ms); return(ms.ToArray()); } }
/// <summary>Parses web data and updates the revoked users hashtable if /// successful</summary> protected void UpdateRl(byte[] data) { // message is length (4) + date (8) + data (variable) + hash (~20) int length = data.Length; if (length < 12) { throw new Exception("No data? Didn't get enough data..."); } length = NumberSerializer.ReadInt(data, 0); DateTime date = new DateTime(NumberSerializer.ReadLong(data, 4)); // warn the user that this is an old revocation list, maybe there is an attack if (date < DateTime.UtcNow.AddHours(-24)) { ProtocolLog.WriteIf(IpopLog.GroupVPN, "Revocation list is over 24 hours old"); } // Weird, data length is longer than the data we got if (length > data.Length - 12) { throw new Exception("Missing data? Didn't get enough data..."); } // hash the data and verify the signature SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); byte[] hash = sha1.ComputeHash(data, 4, length); byte[] signature = new byte[data.Length - 4 - length]; Array.Copy(data, 4 + length, signature, 0, signature.Length); if (!_ca_cert.PublicKey.VerifyHash(hash, CryptoConfig.MapNameToOID("SHA1"), signature)) { throw new Exception("Invalid signature!"); } // convert the data to an array list as it was sent to us MemBlock mem = MemBlock.Reference(data, 12, length - 8); ArrayList rl = AdrConverter.Deserialize(mem) as ArrayList; if (rl == null) { throw new Exception("Data wasn't a list..."); } // convert it into a hashtable for O(1) look ups Hashtable ht = new Hashtable(); foreach (string username in rl) { ht[username] = true; } Interlocked.Exchange(ref _revoked_users, ht); }
public CertificateMaker(byte[] RawData) { _unsigned_data = RawData; Hashtable ht = (Hashtable)AdrConverter.Deserialize(MemBlock.Reference(RawData)); _subject = new DistinguishedName((string)ht["Country"], (string)ht["Organization"], (string)ht["OrganizationalUnit"], (string)ht["Name"], (string)ht["Email"]); RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportCspBlob((byte[])ht["PublicKey"]); _public_key = rsa; _node_address = (string)ht["NodeAddress"]; }
/** * <summary>Disk caching is unsupported at this time.</summary> */ /* When we have a cache miss, we should try to load the data from disk, * if we are successful, we should also delete that file from the disk */ public void CacheMiss(Object o, EventArgs args) { Brunet.Collections.Cache.MissArgs margs = (Brunet.Collections.Cache.MissArgs)args; MemBlock key = (MemBlock)margs.Key; string path = GeneratePath(key); if (File.Exists(path)) { using (FileStream fs = File.Open(path, FileMode.Open)) { ArrayList ht_entries = (ArrayList)AdrConverter.Deserialize(fs); Entry[] entries = new Entry[ht_entries.Count]; int index = 0; foreach (Hashtable entry in ht_entries) { entries[index++] = (Entry)entry; } _data[key] = new LinkedList <Entry>(entries); } File.Delete(path); } }
/// <summary>Create a new revocation message.</summary> public UserRevocationMessage(RSACryptoServiceProvider private_key, string username) { Username = username; int signature_length = private_key.KeySize / 8; byte[] data = null; using (MemoryStream ms = new MemoryStream()) { AdrConverter.Serialize(Username, ms); Random rand = new Random(); NumberSerializer.WriteInt(rand.Next(), ms); NumberSerializer.WriteLong(DateTime.UtcNow.Ticks, ms); data = new byte[ms.Length + signature_length]; ms.Position = 0; ms.Read(data, 0, (int)ms.Length); } SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); Hash = sha1.ComputeHash(data, 0, data.Length - signature_length); Signature = private_key.SignHash(Hash, CryptoConfig.MapNameToOID("SHA1")); Signature.CopyTo(data, data.Length - signature_length); _data = MemBlock.Reference(data); }
public void Test() { CertificateHandler ch = new CertificateHandler(); ch.AddCACertificate(_ca_cert.X509); ch.AddCertificateVerification(this); ArrayList revoked_users = new ArrayList(); revoked_users.Add("joker"); revoked_users.Add("bad_guy"); revoked_users.Add("adversary"); revoked_users.Add("noobs"); // create revocation list byte[] to_sign = null; using (MemoryStream ms = new MemoryStream()) { NumberSerializer.WriteLong(DateTime.UtcNow.Ticks, ms); AdrConverter.Serialize(revoked_users, ms); to_sign = ms.ToArray(); } // sign revocation list SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); byte[] hash = sha1.ComputeHash(to_sign); byte[] signature = _private_key.SignHash(hash, CryptoConfig.MapNameToOID("SHA1")); byte[] data = new byte[4 + to_sign.Length + signature.Length]; NumberSerializer.WriteInt(to_sign.Length, data, 0); to_sign.CopyTo(data, 4); signature.CopyTo(data, 4 + to_sign.Length); UpdateRl(data); X509Certificate likable_guy = CreateCert("likable_guy"); X509Certificate joker = CreateCert("joker"); X509Certificate bad_guy = CreateCert("bad_guy"); X509Certificate good_guy = CreateCert("good_guy"); X509Certificate adversary = CreateCert("adversary"); X509Certificate noobs = CreateCert("noobs"); X509Certificate friendly_guy = CreateCert("friendly_guy"); Assert.IsTrue(ch.Verify(likable_guy, null, _remote_id), "Likable guy"); bool success = false; try { success = ch.Verify(adversary, null, _remote_id); } catch { } Assert.AreEqual(success, false, "adversary"); try { success = ch.Verify(joker, null, _remote_id); } catch { } Assert.AreEqual(success, false, "joker"); Assert.IsTrue(ch.Verify(friendly_guy, null, _remote_id), "friendly guy"); try { success = ch.Verify(noobs, null, _remote_id); } catch { } Assert.AreEqual(success, false, "noobs"); try { success = ch.Verify(bad_guy, null, _remote_id); } catch { } Assert.AreEqual(success, false, "bad_guy"); Assert.IsTrue(ch.Verify(good_guy, null, _remote_id), "good guy"); }
/** * <summary>Retrieves data from the Dht.</summary> * <remarks>First old entries for the key are deleted from the dht, second a * look up is performed, and finally using the token a range of data is * selectively returned.</remarks> * <param name="key">The index used to look up.</summary> * <param name="token">Contains the data necessary to do follow up look ups * if all the data stored in a key is to big for MAX_BYTES.</param> * <returns>IList of hashtables containing the results. Compatible with * DhtGetResult.</returns> */ public IList Get(MemBlock key, byte[] token) { int seen_start_idx = 0; int seen_end_idx = 0; if (token != null) { using (MemoryStream ms = new MemoryStream(token)) { int[] bounds = (int[])AdrConverter.Deserialize(ms); seen_start_idx = bounds[0]; seen_end_idx = bounds[1]; seen_start_idx = seen_end_idx + 1; } } int consumed_bytes = 0; Entry[] data = null; lock (_sync ) { _data.DeleteExpired(key); LinkedList <Entry> ll_data = _data.GetEntries(key); // Keys exist! if (ll_data != null) { data = new Entry[ll_data.Count]; ll_data.CopyTo(data, 0); } } ArrayList result = null; if (data != null) { result = new ArrayList(); ArrayList values = new ArrayList(); int remaining_items = 0; byte[] next_token = null; seen_end_idx = data.Length - 1; for (int i = seen_start_idx; i < data.Length; i++) { Entry e = (Entry)data[i]; if (e.Value.Length + consumed_bytes <= MAX_BYTES) { int age = (int)(DateTime.UtcNow - e.CreateTime).TotalSeconds; int ttl = (int)(e.EndTime - DateTime.UtcNow).TotalSeconds; consumed_bytes += e.Value.Length; Hashtable item = new Hashtable(); item["age"] = age; item["value"] = (byte[])e.Value; item["ttl"] = ttl; values.Add(item); } else { seen_end_idx = i - 1; break; } } remaining_items = data.Length - (seen_end_idx + 1); //Token creation int[] new_bounds = new int[2]; new_bounds[0] = seen_start_idx; new_bounds[1] = seen_end_idx; using (MemoryStream ms = new System.IO.MemoryStream()) { AdrConverter.Serialize(new_bounds, ms); next_token = ms.ToArray(); } result.Add(values); result.Add(remaining_items); result.Add(next_token); } return(result); }
/** * This handles lightweight control messages that may be sent * by UDP */ protected void HandleControlPacket(int remoteid, int n_localid, MemBlock buffer, object state) { int local_id = ~n_localid; UdpEdge e = _id_ht[local_id] as UdpEdge; if (e == null) { return; } if (e.RemoteID == 0) { try { e.RemoteID = remoteid; } catch { return; } } if (e.RemoteID != remoteid) { return; } try { ControlCode code = (ControlCode)NumberSerializer.ReadInt(buffer, 0); if (ProtocolLog.UdpEdge.Enabled) { ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format( "Got control {1} from: {0}", e, code)); } if (code == ControlCode.EdgeClosed) { //The edge has been closed on the other side RequestClose(e); CloseHandler(e, null); } else if (code == ControlCode.EdgeDataAnnounce) { //our NAT mapping may have changed: IDictionary info = (IDictionary)AdrConverter.Deserialize(buffer.Slice(4)); string our_local_ta = (string)info["RemoteTA"]; //his remote is our local if (our_local_ta != null) { //Update our list: TransportAddress new_ta = TransportAddressFactory.CreateInstance(our_local_ta); TransportAddress old_ta = e.PeerViewOfLocalTA; if (!new_ta.Equals(old_ta)) { if (ProtocolLog.UdpEdge.Enabled) { ProtocolLog.Write(ProtocolLog.UdpEdge, String.Format( "Local NAT Mapping changed on Edge: {0}\n{1} => {2}", e, old_ta, new_ta)); } //Looks like matters have changed: this.UpdateLocalTAs(e, new_ta); /** * @todo, maybe we should ping the other edges sharing this * EndPoint, but we need to be careful not to do some O(E^2) * operation, which could easily happen if each EdgeDataAnnounce * triggered E packets to be sent */ } } } else if (code == ControlCode.Null) { //Do nothing in this case } } catch (Exception x) { //This could happen if this is some control message we don't understand if (ProtocolLog.Exceptions.Enabled) { ProtocolLog.Write(ProtocolLog.Exceptions, x.ToString()); } } }
/** * When requests come in this handles it */ public void HandleData(MemBlock payload, ISender ret_path, object state) { Exception exception = null; #if RPC_DEBUG Console.Error.WriteLine("[RpcServer: {0}] Getting method invocation request at: {1}.", _rrman.Info, DateTime.Now); #endif try { object data = AdrConverter.Deserialize(payload); IList l = data as IList; if (l == null) { //We could not cast the request into a list... so sad: throw new AdrException(-32600, "method call not a list"); } string methname = (string)l[0]; #if RPC_DEBUG Console.Error.WriteLine("[RpcServer: {0}] Getting invocation request, method: {1}", _rrman.Info, methname); #endif /* * Lookup this method name in our table. * This uses a cache, so it should be fast * after the first time */ IRpcHandler handler = null; string mname = null; lock ( _sync ) { object[] info = (object[])_method_cache[methname]; if (info == null) { int dot_idx = methname.IndexOf('.'); if (dot_idx == -1) { throw new AdrException(-32601, "No Handler for method: " + methname); } string hname = methname.Substring(0, dot_idx); //Skip the '.': mname = methname.Substring(dot_idx + 1); handler = (IRpcHandler)_method_handlers[hname]; if (handler == null) { //No handler for this. throw new AdrException(-32601, "No Handler for method: " + methname); } info = new object[2]; info[0] = handler; info[1] = mname; _method_cache[methname] = info; } else { handler = (IRpcHandler)info[0]; mname = (string)info[1]; } } ArrayList pa = (ArrayList)l[1]; #if DAVID_ASYNC_INVOKE object[] odata = new object[4]; odata[0] = handler; odata[1] = ret_path; odata[2] = mname; odata[3] = pa; _rpc_command.Enqueue(odata); #else handler.HandleRpc(ret_path, mname, pa, ret_path); #endif } catch (ArgumentException argx) { exception = new AdrException(-32602, argx); } catch (TargetParameterCountException argx) { exception = new AdrException(-32602, argx); } catch (Exception x) { exception = x; } if (exception != null) { //something failed even before invocation began #if RPC_DEBUG Console.Error.WriteLine("[RpcServer: {0}] Something failed even before invocation began: {1}", _rrman.Info, exception); #endif using (MemoryStream ms = new MemoryStream()) { AdrConverter.Serialize(exception, ms); ret_path.Send(new CopyList(PType.Protocol.Rpc, MemBlock.Reference(ms.ToArray()))); } } }
public object Deserialize(Stream stream) { return(AdrConverter.Deserialize(stream)); }
public void Serialize(object obj, Stream stream) { AdrConverter.Serialize(obj, stream); }
public object Deserialize(byte[] b) { return(AdrConverter.Deserialize(b)); }