Material zum Praktikumsversuch Grundpraktikum zur IT
Transcrição
Material zum Praktikumsversuch Grundpraktikum zur IT
Material zum Praktikumsversuch Stand: 22. Dezember 2007, zusammengestellt von: Lijun Liao (Lehrstuhl NDS) Version 1.3 Grundpraktikum zur IT-Sicherheit Automatisierte Bearbeitung von sicheren E-Mails Lehrstuhl für Netz- und Datensicherheit Ruhr-Universität Bochum Bitte beachten Sie, dass dieser Versuch im Raum IC4/58 stattfindet. Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 1 1 Organisation 1.1 Erforderliche Vorkenntnisse zur Teilnahme an diesem Versuch ● ● ● ● ● Vorlesung Kryptographie und Datensicherheit, Prof. Paar. Struktur von Zertifikaten nach X.509. Auszug „Sichere E-Mail“ aus Jörg Schwenk: Sicherheit und Kryptographie im Internet, Vieweg-Verlag 2002 (in Abschnitt 2 auszugsweise abgedruckt). Abschnitt „Using Mail/Signing & Encrypting Messages“ aus Mozilla Help lesen. Java-Grundkenntnisse 1.2 Kontrollfragen Eingangstestat: Sie sollten folgende Fragen beantworten können (bevor der Versuch beginnt): Warum wurde MIME eingeführt? ● Was ist Javamail? ● Was ist BoucyCastle S/MIME Packet? ● Kann BouncyCastle S/MIME Packet ohne Javamail benutzt werden? ● Welche Vorbereitungen müssen Sie treffen, um eine E-Mail an Empfänger A verschlüsseln zu können? ● Welche Vorbereitungen müssen Sie treffen, um eine E-Mail signieren zu können? ● Welche Überprüfungen sollen durchgeführt werden, um die Signatur einer signierten EMail zu verifizieren? 1.3 Auswertungen ● Schriftliche Versuchsauswertung Jedes Team fertigt eine schriftliche Auswertung an. Beantworten Sie darin die Fragen, die zu den jeweiligen Teilversuchen gestellt wurden. Die Versuchsauswertung ist schriftlich beim nächsten Termin mitzubringen. ● Erzeugte E-Mails und der Quellcode Die in diesem Versuch generierten E-Mails und der Quellcode sind per E-Mail bis zum nächsten Termin an den Betreuer Lijun Liao abzugeben. Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 2 2 Bearbeitung von sicheren E-Mails 2.1 Sichere E-Mails Bitte den Kapitel 2 der Versuchsbeschreibung S/MIME lesen. 2.2 Javamail Aus http://java.sun.com/developer/onlineTraining/JavaMail/contents.html 2.2.1 Introduction The JavaMail API [1] is an optional package (standard extension) for reading, composing, and sending electronic messages. You use the package to create Mail User Agent (MUA) type programs, similar to Eudora, Pine, and Microsoft Outlook. Its main purpose is not for transporting, delivering, and forwarding messages like sendmail or other Mail Transfer Agent (MTA) type programs. In other words, users interact with MUA-type programs to read and write emails. MUAs rely on MTAs to handle the actual delivery. 2.2.2 Session The Session class defines a basic mail session. It is through this session that everything else works. The Session object takes advantage of a java.util.Properties object to get information like mail server, username, password, and other information that can be shared across your entire application. The constructors for the class are private. You can get a single default session that can be shared with the getDefaultInstance() method: Properties props = new Properties(); // fill props with any information Session session = Session.getDefaultInstance(props, null); Or, you can create a unique session with getInstance(): Properties props = new Properties(); // fill props with any information Session session = Session.getInstance(props, null); In both cases here the null argument is an Authenticator object which is not being used at this time. More on Authenticator shortly. In most cases, it is sufficient to use the shared session, even if working with mail sessions for multiple user mailboxes. You can add the username and password combination in at a later step in the communication process, keeping everything separate. 2.2.3 Message Once you have your Session object, it is time to move on to creating the message to send. This is done with a type of Message. Being an abstract class, you must work with a subclass, in most cases javax.mail.internet.MimeMessage. A MimeMessage is a email message that understands MIME types and headers, as defined in the different RFCs. Message headers are restricted to US-ASCII characters only, though non-ASCII characters can be encoded in certain header fields. To create a Message, pass along the Session object to the MimeMessage constructor: Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 3 MimeMessage message = new MimeMessage(session); Once you have your message, you can set its parts, as Message implements the Part interface (with MimeMessage implementing MimePart). The basic mechanism to set the content is the setContent() method, with arguments for the content and the mime type: message.setContent("Hello", "text/plain"); If, however, you know you are working with a MimeMessage and your message is plain text, you can use its setText() method which only requires the actual content, defaulting to the MIME type of text/plain: message.setText("Hello"); For plain text messages, the latter form is the preferred mechanism to set the content. For sending other kinds of messages, like HTML messages, use the former. For setting the subject, use the setSubject() method: message.setSubject("First"); 2.2.4 Address Once you've created the Session and the Message, as well as filled the message with content, it is time to address your letter with an Address. Like Message, Address is an abstract class. You use the javax.mail.internet.InternetAddress class. To create an address with just the email address, pass the email address to the constructor: Address address = new InternetAddress( "[email protected]"); If you want a name to appear next to the email address, you can pass that along to the constructor, too: Address address = new InternetAddress( "[email protected]", "George Bush"); You will need to create address objects for the message's from field as well as the to field. Unless your mail server prevents you, there is nothing stopping you from sending a message that appears to be from anyone. Once you've created the addresses, you connect them to a message in one of two ways. For identifying the sender, you use the setFrom() and setReplyTo() methods. message.setFrom(address) If your message needs to show multiple from addresses, use the addFrom() method: Address address[] = ...; message.addFrom(address); For identifying the message recipients, you use the addRecipient() method. This method requires a Message.RecipientType besides the address. message.addRecipient(type, address) The three predefined types of address are: • Message.RecipientType.TO Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 4 • • Message.RecipientType.CC Message.RecipientType.BCC So, if the message was to go to the vice president, sending a carbon copy to the first lady, the following would be appropriate: Address toAddress = new InternetAddress("[email protected]"); Address ccAddress = new InternetAddress("[email protected]"); message.addRecipient(Message.RecipientType.TO, toAddress); message.addRecipient(Message.RecipientType.CC, ccAddress); The JavaMail API provides no mechanism to check for the validity of an email address. While you can program in support to scan for valid characters (as defined by RFC 822) or verify the MX (mail exchange) record yourself, these are all beyond the scope of the JavaMail API. 2.2.5 Authenticator Like the java.net classes, the JavaMail API can take advantage of an Authenticator to access protected resources via a username and password. For the JavaMail API, that resource is the mail server. The JavaMail Authenticator is found in the javax.mail package and is different from the java.net class of the same name. The two don't share the same Authenticator as the JavaMail API works with Java 1.1, which didn't have the java.net variety. To use the Authenticator, you subclass the abstract class and return a PasswordAuthentication instance from the getPasswordAuthentication() method. You must register the Authenticator with the session when created. Then, your Authenticator will be notified when authentication is necessary. You could popup a window or read the username and password from a configuration file (though if not encrypted it is not secure), returning them to the caller as a PasswordAuthentication object. Properties props = new Properties(); // fill props with any information Authenticator auth = new MyAuthenticator(); Session session = Session.getDefaultInstance(props, auth); 2.2.6 Transport The final part of sending a message is to use the Transport class. This class speaks the protocol-specific language for sending the message (usually SMTP). It's an abstract class and works something like Session. You can use the default version of the class by just calling the static send() method: Transport.send(message); Or, you can get a specific instance from the session for your protocol, pass along the username and password (blank if unnecessary), send the message, and close the connection: message.saveChanges(); // implicit with send() Transport transport = session.getTransport("smtp"); transport.connect(host, username, password); transport.sendMessage(message, message.getAllRecipients()); transport.close(); Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 5 This latter way is best when you need to send multiple messages, as it will keep the connection with the mail server active between messages. The basic send() mechanism makes a separate connection to the server for each method call. Note: To watch the mail commands go by to the mail server, set the debug flag with session.setDebug(true). 2.2.7 Store and Folder Getting messages starts similarly to sending messages, with a Session. However, after getting the session, you connect to a Store, quite possibly with a username and password or Authenticator. Like Transport, you tell the Store what protocol to use: // Store store = session.getStore("imap"); Store store = session.getStore("pop3"); store.connect(host, username, password); After connecting to the Store, you can then get a Folder, which must be opened before you can read messages from it: Folder folder = store.getFolder("INBOX"); folder.open(Folder.READ_ONLY); Message message[] = folder.getMessages(); For POP3, the only folder available is the INBOX. If you are using IMAP, you can have other folders available. Note: Sun's providers are meant to be smart. While Message message[] = folder.getMessages(); might look like a slow operation reading every message from the server, only when you actually need to get a part of the message is the message content retrieved. Once you have a Message to read, you can get its content with getContent() or write its content to a stream with writeTo(). The getContent() method only gets the message content, while writeTo() output includes headers. System.out.println(((MimeMessage)message).getContent()); Once you're done reading mail, close the connection to the folder and store. folder.close(aBoolean); store.close(); The boolean passed to the close() method of folder states whether or not to update the folder by removing deleted messages. 2.3 BouncyCastle Bibliotheken Wir benutzten BouncyCastle S/MIME Packet von the Legion of Bouncy Castle [2] zur Bearbeitung von S/MIME E-Mails mit Hilfe von JavaMail [1]. 2.3.1 Hinzufügen des Providers BouncyCastle if(Security.getProvider("BC") == null) Security.addProvider(new BouncyCastleProvider()); Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 6 2.3.2 Lesen vom privaten Schlüssel und Zertifikaten aus der PKCS12-Ke ystore Datei KeyStore ks = KeyStore.getInstance("PKCS12", "BC"); ks.load(new FileInputStream(keystoreFilename), keyStorePassword.toCharArray()); Enumeration e = ks.aliases(); String keyAlias = null; while (e.hasMoreElements()){ String alias = (String)e.nextElement(); if (ks.isKeyEntry(alias)) keyAlias = alias; } if (keyAlias == null) throw new Exception("can't find a private key!"); PrivateKey signKey = (PrivateKey) ks.getKey(keyAlias, null); // The first certificate is the certificate of the signer, all // others, if exist, are the CA certificates Certificate[] certs = ks.getCertificateChain(keyAlias); 2.3.3 Lesen eines Zertifikats aus der Zertifikat-Datei CertificateFactory cf = CertificateFactory.getInstance( "X509", "BC"); X509Certificate cert = (X509Certificate) cf.generateCertificate(new FileInputStream(certFile)); 2.3.4 Erzeugung einer signierten S/MIME E-Mail // create the generator for creating an smime/signed message SMIMESignedGenerator gen = new SMIMESignedGenerator(); /* add a signer to the generator - this specifies we are using SHA1 * and adding the smime attributes above to the signed attributes * that will be generated as part of the signature. The encryption * algorithm used is taken from the key */ gen.addSigner( signKey, // The signing key instance of PrivateKey signCert, // The signing certificate instanceof X509Certificate SMIMESignedGenerator.DIGEST_SHA1, // Using hash algorithm SHA1 new AttributeTable(signedAttrs), // The attributes to be signed null); // create a CertStore containing the certificates we want carried // in the signature CertStore certsAndcrls = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certsAndCrlsCollection), "BC"); // add our pool of certs and cerls (if any) to go with the signature gen.addCertificatesAndCRLs(certsAndcrls); // Sign the MimeBodyPart and extract the multipart object from the Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 7 // SMIMESigned object. MimeMultipart mm = gen.generate(mimeBodyPart, "BC"); // Set the signed multipart as the content of a mime message MimeMessage mimemsg = ... mimemsg.setContent(mm, mm.getContentType()); ... 2.3.5 Verifizierung einer signierten S/MIME E-Mail MimeMessage msg = ...; // First construct an SMIMESigned object SMIMESigned smimeSigned = null if (msg.isMimeType("multipart/signed")){ smimeSigned = new SMIMESigned( (MimeMultipart)msg.getContent()); } else if (msg.isMimeType("application/pkcs7-mime")) { // in this case the content is wrapped in the signature block. smimeSigned = new SMIMESigned(msg); } // Get the signed content MimeBodyPart bodyPart = smimeSigned.getContent(); Object content = bodyPart.getContent(); if(content instanceof String){ ... } else if(content instanceof Multipart){ ... } // Get all certificates and crls passed in the signature CertStore certs = s.getCertificatesAndCRLs( "Collection", "BC"); // Get the signer SignerInformationStore signers = s.getSignerInfos(); Collection c = signers.getSigners(); SignerInformation signer = (SignerInformation) c.iterator().next(); // Get the signing certificate Collection signerCerts = certs.getCertificates(signer.getSID()); X509Certificate signingCert = (X509Certificate) signerCerts.iterator().next(); // Create a cert selector for the building of certpath X509CertSelector certSelector = new X509CertSelector(); certSelector.setCertificate(signingCert); certSelector.setCertificateValid(signingTime); // Try to build a valid certpath CertPathBuilder cpbuilder = CertPathBuilder.getInstance( "PKIX", "BC"); PKIXBuilderParameters params = new PKIXBuilderParameters( trustAnchors, certSelector); params.setRevocationEnabled(false); Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 8 params.addCertStore(certs); params.setDate(signingTime); // CertPathBuilderException is raised if no valid certpath is found cpbuilder.build(params); // Verify the signature with the signing certificate boolean result = signer.verify(signingCert, "BC"); 2.3.6 Erzeugung einer verschlüsselten S/MIME E-Mail // create the generator for creating an smime/encrypted message SMIMEEnvelopedGenerator gen = new SMIMEEnvelopedGenerator(); // Add the certificate of the recipients, usually also of the sender gen.addKeyTransRecipient(recipientCert1); // The OID is defined in the class SMIMEEnvelopedGenerator String symmetricAlgoOID = SMIMEEnvelopedGenerator.*; MimeBodyPart mp = gen.generate( mimeBodyPart, symmetricAlgoOID, "BC"); // Set the signed multipart as the content of a mime message MimeMessage mimemsg = ... mimemsg.setContent(mm, mm.getContentType()); ... 2.3.7 Entschlüsselung einer verschlüsselten S/MIME E-Mail // First read the private key and the certificate from the key store PrivateKey privKey = ...; X509Certificate cert = ...; RecipientId recId = new RecipientId(); recId.setSerialNumber(cert.getSerialNumber()); recId.setIssuer(cert.getIssuerX500Principal().getEncoded()); // Get the recipient information for this recipient SMIMEEnveloped m = new SMIMEEnveloped(mimemsg); RecipientInformationStore recipients = m.getRecipientInfos(); RecipientInformation recipient = recipients.get(recId); byte[] contentBytes = recipient.getContent(privKey, "BC"); MimeBodyPart decContent = SMIMEUtil.toMimeBodyPart(contentBytes); ... 3 Versuche Nach den einleitenden Informationen erhalten Sie nun eine konkrete Versuchsbeschreibung. Auf jedem Rechner ist die Java-Entwicklungsumgebung von Eclipse (Version 3.2) und die Java Developement Kit (Version 1.5.0) installiert. Alle Zertifikate und privaten Schlüssel sind unter dem Verzeichnis ~/workspace/GPJavamail/key gespeichert. ca.cer ist das CA-Zertifikat. Das entsprechende Zertifikat für den Kontonamen pcZXY ist pcZXY.cer, und der entsprechende private Schlüssel ist pcZXY.p12 mit dem Passphrase kspwd und alias pcZXY. Alle Benutzer-Zertifikate sind vom ca.cer ausgestellt. Schritt 1: Loggen Sie sich als Benutzer praktikum ein. Konfigurieren Sie Ihren Mozilla E-Mail-Client mit der E-Mail-Adresse [email protected]. pcZXY ist dabei der Name des Rechners, an dem Sie gerade arbeiten (Beschriftung beachten!). Die Kontonamen für die E-Mail-Adressen sind identisch mit den Rechnernamen: pc011, pc012, pc013, pc014, pc015 im Subnetz netz0.test Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 9 pc112, pc113, pc114, pc115, pc116, pc117, pc118 im Subnetz netz1.test pc211, pc212, pc213, pc214, pc215 im Subnetz netz2.test Die Passwörter sind identisch mit den Kontonamen bzw. Rechnernamen. Die Einträge für die IMAP- (NICHT POP3) und SMPT-Server lauten: server0.netz0.test server1.netz1.test server2.netz2.test. Konfigurieren Sie ca.cer as trusted CA und importieren Sie Ihren privaten Schlüssel. Starten Sie die Java-Entwicklungsumgebung von Eclipse (~> eclipse-3.2) und öffnen Sie das Java-Projekt GP-Javamail. Die nächsten Schritte beziehen sich auf die Arbeit in dieser Entwicklungsumgebung. Schritt 2: Öffnen Sie die abstrakte Klasse nds.smime.SMIMEGenerator. Versuchen Sie diese Klasse anhand der Kommentare, besonders mit dem Wort TODO, in der Datei zu vervollständigen. Nutzen Sie bitte SHA256 und SHA512 nicht, da dieser Algorithmus vom Mail-Client nicht verarbeitet wird. Schritt 3: Erstellen Sie einen Verzeichnis ~/pcZXY. Öffnen Sie die Klasse nds.smime.SignedSMIMEGenerator. Versuchen Sie diese Klasse anhand der Kommentare, besonders mit dem Wort TODO, in der Datei zu vervollständigen. Erzeugen Sie mit Hilfe dieser Klasse eine signierten S/MIME E-Mail. 1. Speichern Sie diese E-Mail lokal unter ~/pcZXY/signed_local.eml. 2. Schicken Sie diese E-Mail an alle Mailadressen (auch an Sie selbst) im Netzwerklabor. Speichern Sie diese E-Mail in Mozilla unter ~/pcZXY/signed_server.eml. Schritt 4: Öffnen Sie die Klasse nds.smime.SignedSMIMEReader. Versuchen Sie diese Klasse anhand der Kommentare, besonders mit dem Wort TODO, in der Datei zu vervollständigen. Betrachten Sie im folgenden Fällen ca.cer als TrustAnchor. 1. Verifizieren Sie mit Hilfe dieser Klasse die E-Mail in ~/pcZXY/signed_local.eml aus Schritt 3. 2. Kopieren Sie die Datei ~/pcZXY/signed-local.eml nach ~/pcZXY/signed_local_modified.eml und modifizieren Sie die letzte Datei. Verifizieren Sie dann die modifizierte E-Mail. 3. Verifizieren Sie alle signierten Nachrichten von Ihrem Konto. Versuchsauswertung: Dokumentieren Sie die Ausgabe des Programms. Schritt 5: Öffnen Sie die Klasse nds.smime.SignedSMIMEReader. Betrachten Sie im folgenden Fällen otherCa.cer als TrustAnchor. Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 1 1. Verifizieren Sie mit Hilfe dieser Klasse die E-Mail in ~/pcZXY/signed_local.eml aus Schritt 3. 2. Verifizieren Sie alle signierten Nachrichten von Ihrem Konto. Versuchsauswertung: Dokumentieren Sie die Ausgabe des Programms. Schritt 6: Öffnen Sie die Klasse nds.smime.EncryptedSMIMEGenerator. Versuchen Sie diese Klasse anhand der Kommentare, besonders mit dem Wort TODO, in der Datei zu vervollständigen. Erzeugen Sie mit Hilfe dieser Klasse eine verschlüsselte S/MIME E-Mail. 1. Speichern Sie diese E-Mail lokal unter ~/pcZXY/encrypted_local.eml. 2. Schicken Sie diese E-Mail an alle Mailadressen im Netzwerklabor. Speichern Sie diese E-Mail in Mozilla unter ~/pcZXY/encrypted_server.eml. Schritt 7: Öffnen Sie die Klasse nds.smime.EncryptedSMIMEReader. Versuchen Sie diese Klasse anhand der Kommentare, besonders mit dem Wort TODO, in der Datei zu vervollständigen. 1. Entschlüsseln Sie mit Hilfe dieser Klasse die E-Mail in ~/pcZXY/encrypted_local.eml aus Schritt 6. 2. Entschlüsseln Sie alle verschlüsselten Nachrichten von Ihrem Konto. Versuchsauswertung: Dokumentieren Sie die Ausgabe des Programms. Literatur [1] SUN. JavaMail API. URL: http://java.sun.com/products/javamail/ [2] The Legion of the Bouncy Castle. Specifications of the Bouncy Castle Crypto package. URL: http://bouncycastle.org/specifications.html Praktikumsversuch auto. Bearbeitung von sicheren E-Mails Lehrstuhl Netz- und Datensicherheit 1