Level: elementary Todd sundsted, chief designer, pointfire, Inc October 07, 2001
Secure Communication between peers is a core requirement for any important P2P applications. Although security details depend on how the application is used and what the application is going to protect, it is generally possible to implement robust and general-purpose security by using existing technologies such as SSL. This month, Todd sundsted demonstrated how to use SSL (through JSSE) in P2P security ).
Last month, we checked the trust roles in P2P applications. The level of trust is a measure of our degree of confidence, that is, whether the people we are communicating with are what we think, and whether the resources we are accessing are what we think. We have also studied the three components used to build a trusted role in all distributed applications, including P2P applications: authentication, authorization, and encryption. Now we will apply the last month's course to practice by modifying our simple P2P application. In particular, we will use X.509 certificates to extend the application to support P2P authentication and encryption. We will handle authorization issues in future articles. Security Authentication The security requirements of an application depend heavily on how the application will be used and what the application will be protected. However, it is generally possible to use existing technologies to achieve powerful and general-purpose security. Authentication is a good example. When a customer wants to buy a product from a web site, both the customer and the Web site must undergo authentication. A customer uses a name and password to authenticate himself. On the other hand, a web site authenticates itself by exchanging a piece of signature data and a valid X.509 Certificate (as part of the SSL handshake. The customer's browser verifies the certificate and verifies the signature data with the attached public key. Once both parties are certified, the transaction can begin. SSL can use the same mechanism to process server authentication (as in the preceding example) and client authentication. A web site typically does not rely on SSL for client authentication-it is easier for users to provide passwords. Ssl client and server authentication is perfect for transparent authentication, and transparent authentication will certainly occur between peers in P2P applications. Secure Socket Layer (Secure Sockets Layer (SSL ))SSL is a security protocol that provides privacy for communications over networks (such as the Internet. SSL prevents applications from being stolen or tampered with during communication. SSL is actually two protocols that work together: "SSL record protocol" and "SSL handshake protocol ). The "SSL record protocol" is a lower-level protocol of the two protocols. It is a higher-level protocol. For example, the SSL handshake protocol encrypts and decrypts long data records. The SSL handshake protocol processes the exchange and verification of application creden. When an application (client) wants to communicate with another application (server), the client opens a socket connection connected to the server. Then, the client and the server negotiate the secure connection. As part of the negotiation, the server authenticates itself to the client. The client can choose to perform authentication on the server or not. Once authentication is completed and a secure connection is established, the two applications can communicate securely. For more information about SSL, see references. By convention, I will regard the peer that initiates the communication as a client, and the other as a server, No matter what role they play after the connection.
How to use SSL in Java applications SSL for Java applications is provided by Java Secure Socket Extension (JSSE. JSSE is a standard part of the latest release of JDK 1.4 beta, but is available as an extension for earlier Java platforms. JSSE uses SSL as its underlying mechanism for secure sockets. In addition to transparent authentication and encryption, JSSE secure sockets work in a similar way as conventional sockets. Because they also look like common Sockets (they are Classjava.net.Socket And classjava.net.ServerSocket So most code using JSSE does not need to be modified. The Code most affected is the code that processes the creation and initialization of the Secure Socket factory. If you want to use JSSE on a Java platform earlier than version 1.4, you will have to download and install the JSSE extension by yourself (see references ). The installation instructions are very simple, so I don't want to repeat them here.
Model Figure 1 shows the role that SSL will play in the communication between the peer. Figure 1. Working SSL
The two ECSS named a and B want to communicate securely. In our simple P2P application environment, server a wants to query a resource on server B. Each peer has a database (named keystore) containing its private key and a certificate containing its public key. Password protects the content of the database. The database also contains one or more self-signed certificates from trusted peers. Peer machine a initiates this transaction, and each peer machine authenticates each other. The password and length used by the two peer machines for negotiation are used and a secure channel is established. After completing these operations, each peer knows who it is talking to and that the channel is secure.
Initialization Because the introduction of JSSE and SSL has a great impact on the initialization code, let's examine the code for initialization in peer machine. List 1. Security Initialization code
// Each peer has an identity that must be locally (but not globally) // unique. This identity and its associated public and private keys // are stored in a keystore and protected by a password. Each // peer also has a name that must be globally unique. String stringIdentity = null; String stringPassword = null; String stringName = null; // The code that prompts the user for his/her identity // and password goes here. the user's name is // generated (if necessary) later. // Create home directory. This is a very portable way // to create a home directory, but it has its problems -- // the various flavors of Microsoft Windows put the directory // in widely different locations in the directory hierarchy. String stringHome = System.getProperty("user.home") + File.separator + "p2p"; File fileHome = new File(stringHome); if (fileHome.exists() == false) fileHome.mkdirs(); // Create keystore. We must run an external process to create the // keystore, because the security APIs don't expose enough // functionality to do this inline. I haven't tested this widely enough // to know how portable this code is, but it works on everything I // tried it on. String stringKeyStore = stringHome + File.separator + "keystore"; File fileKeyStore = new File(stringKeyStore); if (fileKeyStore.exists() == false) { System.out.println("Creating keystore..."); byte [] arb = new byte [16]; SecureRandom securerandom = SecureRandom.getInstance("SHA1PRNG"); securerandom.nextBytes(arb); stringName = new String(Base64.encode(arb)); String [] arstringCommand = new String [] { System.getProperty("java.home") + File.separator + "bin" + File.separator + "keytool", "-genkey", "-alias", stringIdentity, "-keyalg", "RSA", "-keysize", "1024", "-dname", "CN=" + stringName, "-keystore", stringHome + File.separator + "keystore", "-keypass", stringPassword, "-storetype", "JCEKS", "-storepass", stringPassword }; Process process = Runtime.getRuntime().exec(arstringCommand); process.waitFor(); InputStream inputstream2 = process.getInputStream(); IOUtils.copy(inputstream2, System.out); InputStream inputstream3 = process.getErrorStream(); IOUtils.copy(inputstream3, System.out); if (process.exitValue() != 0) System.exit(-1); } // Once the application has created/located the keystore, it // opens it and creates a KeyStore instance from the data // in it. char [] archPassword = stringPassword.toCharArray(); FileInputStream fileinputstream = new FileInputStream(stringHome + File.separator + "keystore"); KeyStore keystore = KeyStore.getInstance("JCEKS"); try { keystore.load(fileinputstream, archPassword); } catch (IOException ioexception) { System.out.println("Cannot load keystore. Password may be wrong."); System.exit(-3); } if (keystore.containsAlias(stringIdentity) == false) { System.out.println("Cannot locate identity."); System.exit(-2); } // Create key manager. The key manager holds this peer's // private key. KeyManagerFactory keymanagerfactory = KeyManagerFactory.getInstance("SunX509"); keymanagerfactory.init(keystore, archPassword); KeyManager [] arkeymanager = keymanagerfactory.getKeyManagers(); // Create trust manager. The trust manager hold other peers' // certificates. TrustManagerFactory trustmanagerfactory = TrustManagerFactory.getInstance("SunX509"); trustmanagerfactory.init(keystore); TrustManager [] artrustmanager = trustmanagerfactory.getTrustManagers(); // Create SSL context. SSLContext sslcontext = SSLContext.getInstance("SSL"); SecureRandom securerandom = SecureRandom.getInstance("SHA1PRNG"); sslcontext.init(arkeymanager, artrustmanager, securerandom); // Create factories. m_socketfactory = sslcontext.getSocketFactory(); m_serversocketfactory = sslcontext.getServerSocketFactory(); m_keystore = keystore;
|
When you start the application for the first time, the application prompts you to enter an identity (alias) and a password. Identity is only used for local identification of the peer-to-peer-it has no global significance. The application generates a random 128-bit (16-byte) string, which is used by the application to globally identify the peer and convert it into a letter/number string. The application uses its identity, password, and name to create a keystore and a public/private key pair. The key pair is stored in the keystore. Password to protect the information in the keystore. I'm sure you have noticed how I took the initial keystore. The application starts the keytool as an external process, and the keytool creates the keystore. I have to do this because public Java security APIs do not provide tools for creating certificates-these functions are hidden in JSSE and their APIs are not released. The biggest disadvantage of starting keytool to create keystore is that the password provided by the user is exposed. The password provided by the user is passed in as part of the parameter list. After the application creates a keystore, it opens the keystore and loads it into the memory (if we can directly create a keystore, we can skip this step ). The application createsKey Manager)And oneTrust Manager). The key Manager manages the key, which is used to authenticate it on the Peer of the application opposite to the secure socket. The trust Manager manages certificates used to authenticate the peer on the other end of the Secure Socket. Finally, the application createsSSLContext Instance, which acts as the factory of the Secure Socket factory. Application CreationSocketFactory AndServerSocketFactory And use them for later communication. |