Background
Microsoft's Peer-to-Peer Grouping technology provides a stable, reliable, and robust infrastructure for Windows peer-to-peer applications to communicate. Peers use Peer Name Resolution Protocol (PNRP - a serverless DNS) to register and discover other peers within a group. Groups provide a secure mechanism for connecting peers, services, and resources within a peer network. Grouping allows data to be passed between peers efficiently, reliably, and securely.
Microsoft's entire Peer-to-Peer technology is exposed through the latest Platform SDK as C/C++ API calls. However, the code in this article shows these APIs being used from .NET managed code using C#.
Introduction
This article introduces new peer-to-peer group concepts. Unlike graphs, groups provide a flexible security model in which peers have secure identities and must be invited to a group. Peers must join an existing group using their secure identity before they can publish records and interact with other peers. The following sections summarize some of the core concepts needed to understand the grouping APIs. The remainder of the article provides more detail about identities, including a sample application demonstrating how to use them.
Concepts
Identity
Before a peer can create or join a group, it must have an identity. This identity uniquely identifies the peer within a group. A peer identity is an XML blob containing a base-64 encoded certificate that contains the RSA public key assigned to it. This identity can be exported to a file, copied to another computer, and imported. The following shows an identity exported to XML:
<PEERIDENTITYEXPORT VERSION="1.0">
<PEERNAME>7459f0128f3b452e621df6fd3ed5fe3b7581c148.User1</PEERNAME>
<DATA xmlns:dt="urn:schemas-microsoft-com:datatypes" dt:dt="bin.base64">
TQBJAEkASABDAEEASQBCAEEAegBDAEMAQgBzAFEARwBDAFMAcQBHAFMASQBiADMARABRAEUA
SABBAGEAQwBDAEIAcgBVAEUAZwBnAGEAeABNAEkASQBHAHIAVABDAEMAQQA3ADQARwBDAFMA
cQBHAFMASQBiADMARABRAEUASAANAAoAQQBhAEMAQwBBADYAOABFAGcAZwBPAHIATQBJAEkA
...
agBqAEsAawAwAEMASABrAHgASQBEAHkAcAAzAEsAZQBPAEEAZwBJAEgAMABBAD0APQANAAoA
</DATA>
</PEERIDENTITYEXPORT>
Each identity has a set of credentials that is used to verify membership when connecting to a peer-to-peer group. These credentials are represented as chains of X.509 certificates called Group Membership Certificates.
Peer Group
Once you have an identity, you can create a peer-to-peer group. The creator of a group becomes the owner and initial administrator of the group. This administrator can then invite other peers as either limited members or share the role of administrator.
Invitations
Only an administrator of a group can creator or refresh an invitation. Creating an invitation requires the creator's identity, the role to be given to the identity being created (administrator or member), and a date when the membership expires. Creating an invitation results in an XML blob that can be exported to a file, sent to the peer (by copying the file or sending it by e-mail), and finally imported by the peer. Existing memberships can be refreshed with an expiration date further in the future by reissuing an invitation. In this case, the invitation can either be sent to the peer who must re-join the group, or the invitation can be published to the group and automatically picked up by the peer the next time it synchronizes.
Joining
Joining a group requires an invitation provided by an administrator of the group. If the invitation includes an expiration date, eventually your membership will expire and be deleted (unless the invitation is refreshed by an administrator). However, it is possible to create an invitation that does not expire.
Membership
Members with the administrator role can issue invitations, refresh credentials, and manage records published to the group. Normal members can only add or modify records published to the group. There is no ability to create custom roles.
The records published to a group use the same attribute schema and searching mechanism used by peer graphs. Groups include the same ability to create direct connections between peers, and send and receive private data messages. The grouping API includes events to indicate live changes. Finally, a group's database can be exported and imported in the same manner as a graph.
Of Interest
Anyone who has ever used Groove will immediately recognize the similarity between peer-to-peer groups and Groove's workspaces. After installing Groove, you first create an identity which uniquely identities you. After this, you can create groups (workspaces) from pre-configured templates such as files, discussions, meetings, etc. You can install Groove on up to five computers that you own, and synchronize these workspaces between all computers. You can also invite other identities (contacts) to share a given workspace. Each workspace has different roles that determines the capabilities of an identity (manager, participant, guest). A workspace also has permissions that determines what each role can do in the workspace (create, edit, delete, etc.).
PeerIdentity Class
The PeerIdentity
class wraps all the functionality of the underlying Identity APIs. Each instance of a PeerIdentity
object represents the properties and behavior of a single identity. Internally, a marshaled form of the PEER_NAME_PAIR
data structure is maintained. Two fields of this data structure are exposed as properties.
The Identity
property is read-only and exposes the name associated with the identity.
public string Identity
{
get
{
return data.pwzPeerName;
}
}
The FriendlyName
property exposes the friendly name of the identity. Setting a new friendly name results in calling the underlying PeerIdentitySetFriendlyName
API method.
public string FriendlyName
{
get
{
return data.pwzFriendlyName;
}
set
{
uint hr = PeerIdentityNative.PeerIdentitySetFriendlyName(Identity, value);
if (hr != 0) throw new PeerIdentityException(hr);
data.pwzFriendlyName = value;
}
}
The PeerIdentity
class also provides a read-only Xml
property which returns the XML representation of the identity used for importing or exporting the identity. The underlying PeerIdentityGetXML
API method is used to get the XML fragment as a string.
public string Xml
{
get
{
string xml;
uint hr = PeerIdentityNative.PeerIdentityGetXML(Identity, out xml);
if (hr != 0) throw new PeerIdentityException(hr);
return xml;
}
}
Creating an Identity
The PeerIdentity
Create
method is static
(Shared
) and takes two parameters; name and friendly name. Either or both parameters can be blank. This method uses the underlying PeerIdentityCreate
API to create and return the identity.
public static string Create(string Name, string FriendlyName)
{
IntPtr nameptr = IntPtr.Zero;
if (Name != string.Empty)
nameptr = Marshal.StringToHGlobalUni(Name);
IntPtr friendptr = IntPtr.Zero;
if (FriendlyName != string.Empty)
friendptr = Marshal.StringToHGlobalUni(FriendlyName);
string identity;
uint hr = PeerIdentityNative.PeerIdentityCreate(
nameptr, friendptr, IntPtr.Zero, out identity);
if (hr != 0) throw new PeerIdentityException(hr);
return identity;
}
The following table shows the results of passing various parameter values and the resulting identity.
Name Parameter |
FriendlyName Parameter |
Resulting Identity |
|
|
e9ac83642fc11fb162936e51a5586f1ce 4d6e426 |
James Bond |
|
90cb9594c3512104971e91111efd1387 c168be37. James Bond |
|
james.bond@mi5.gov.uk |
1d962f531c13b5a8031bb8ea905782dac fb9d74b |
Exporting an Identity
The PeerIdentity Export
method encrypts the identity with a password and returns an XML fragment. This method wraps the underlying PeerIdentityExport
API method.
public string Export(string Password)
{
string xml;
uint hr = PeerIdentityNative.PeerIdentityExport(
Identity, Password, out xml);
if (hr != 0)
throw new PeerIdentityException(hr);
return xml;
}
Importing an Identity
The PeerIdentity
Import
method attempts to decrypt an XML fragment using the given password. If the XML fragment was not generated by the Export
method, the password is incorrect or the identity already exists, and an exception is thrown. This method wraps the unmanaged PeerIdentityImport
API method.
public static string Import(string Xml, string Password)
{
string identity;
uint hr = PeerIdentityNative.PeerIdentityImport(Xml,
Password, out identity);
if (hr != 0)
{
throw new PeerIdentityException(hr);
}
return identity;
}
Group Membership of an Identity
The PeerIdentity
Groups
property allows you to get a list of the groups to which the identity is a member. This property returns a PeerGroupCollection
class which implements the standard IEnumerable
interface. PeerGroupCollection
uses the unmanaged PeerEnumGroups
API to return and enumerate the groups to which an identity is a member.
Listing Existing Identities
To get a list of the current identities created for the Windows user account, use the PeerIdentityCollection
class in a foreach
loop. This class supports the standard IEnumerable
interface. PeerIdentityCollection
uses the unmanaged PeerEnumIdentities
API to return and enumerate the existing identities.
Using the Sample Application
The sample application allows you to manage your identities. Features of a PeerIdentity
are divided into different tabs; listing existing identities, creating, exporting, importing, and listing the groups of which the identity is a member.
The Identities tab shows a list of existing identities created for the current Windows user account (see image above). The properties of the corresponding PeerIdentity
object are displayed in a property grid. You can modify the friendly name by entering a new name and pressing Enter. The delete button allows you to delete the selected identity.
The Create tab lets you enter the name of the identity and a friendly name (usually an e-mail address). Press the Create button to see the secure peer name returned. The following image shows an example:
The Export tab lets you see the XML fragment generated by the Export method and save this identity to a file. First, select an identity on the Identities tab. Next, you must enter a password to encrypt the identity. Click the Export button to generate the XML fragment. Click the Save As button to save the XML fragment to a file. The following image shows an example:
The Import tab lets you import a previous exported identity. Enter the password used to encrypt the identity in the file being imported. Next, click the Import button to select a file and import it. A message box is displayed if an error occurs, otherwise, the secure peer name of the identity is displayed. The demo includes an example identity exported by the author which you can import (the password is 'test'). The following image shows an example:
The Groups tab shows you the groups of which the selected identity is a member. The controls on this tab will be blank until the next article shows how to create and join groups.
Point of Interest
The peer-to-peer identity API also supports the ability to use a custom cryptographic service provider to encrypt identities. However, due to its complexity, this feature has not been exposed in managed code.
Also, Windows Vista includes an additional method to return the default identity of the current Windows user account. While the code for this is included, it has not been tested and will certainly throw an exception on Windows XP SP2.
Links to Resources
I have found the following resources to be very useful in understanding peer graphs:
Conclusion
I hope you have found this article useful. I will be writing more articles on the following subjects to further your understanding of Microsoft's Peer-to-Peer technology:
- Peer Groups - Create, Open, and Delete
- Peer Groups - Invitations and Joining
- Peer Collaboration - People Near Me
- Peer Collaboration - EndPoints
- Peer Collaboration - Capabilities
- Peer Collaboration - Presence
- Peer Collaboration - Invitations
- Peer Name Resolution - Windows Vista Enhancements
If you have suggestions for other topics, please leave a comment.
History