Alice -------- ( Eve )-------- Bob
-------------------------- -------------------------- | Alice |----( Eve )---| Bob | | encrypt(Hello) = x5!$b | | decrypt(x5!$b) = Hello | -------------------------- --------------------------so that the true message is hidden from Eve.
$ openssl md5 filename $ openssl sha1 filenameChange one character in the file, and try again.
$ openssl des -in lecture.html -out lecture.des \ -K 1234567812345678 -iv abcdabcdabcdabcd $ openssl des -d -in lecture.des -out \ lecture-decoded.html -K 1234567812345678 -iv abcdabcdabcdabcdNote that here the 56-bit key is given as a 16 hex char string. (Or you provide a password that is used to access the key in a locked file.)
[msie@bob rsa-example]$ openssl genrsa -out private-1024.pem 1024 Generating RSA private key, 1024 bit long modulus .........................................++++++ ....++++++ e is 65537 (0x10001) [msie@bob rsa-example]$ cat private-1024.pem -----BEGIN RSA PRIVATE KEY----- MIICXQIBAAKBgQDG4QTKUK6WbYvnaY1tXcCtUmfOW2eTnldcgSq4/t+ZVsWU5wmD Zcq6ncOGu8pkooyYQeReOuifSye6GMQudfD4ej9PKhDrH7gQcQJk2vV01ojPlYG5 t5O6Coi7TvQy29waIOjThAqtg4H7Le4w0f4g0MJMlyOs3TKnz0qFx5jIqQIDAQAB AoGAEjhDLBXAKN/YVVcCMebI5BgMkoclMgzri/n5ZAFVksK0TzPrVzJYJEiXxRwn KpkJsFk5Brj23sEP3qiuMGN1s+R/zhCZpkk0A9rHVL7hHS+m51J+4jezbndcBIf5 4wIisa5H7qVQHSuR0iHclXV87oyDv2axNKJsgXE54vUIeEECQQDqSz3+AXrQLKX2 +0kQJFSQ8tprT9i81FKUkjeqqAbqcdoApPeFrah9ImFUh1+Cv/MO2QewMSbhO20+ VmfkwjMFAkEA2U3W02KLpeq1vfFMTjvjsV8VVvTKWzXYlsYU9ANjitcSNKmj1B59 yjYVg39n/XIyIVKsqjRishFUPvI7m734VQJBAKpenG2gVdYbIXQ/thlu0a+1aO6v 2UM2gfZXfPMzzBOfRo9BZlxmsyaLYYs+BU3mlrAtUVHl7AfMVtwFqPbH4KECQQC7 ch2hchwsHu5uzjqYMakTU4XA4J+9VhFi3bMtWc7/8M3Ph5W+YB750vVz3O8C/QKp I/u1RkLsf25AbgtlKNWRAkAhNgH25llu4yKICbh1EWRpBPIsb9E3GR5gaSSC4q2W Scmp7BEAcZdv51snJOGwbNlyPsz/xz8rcreKAsAkl+xi -----END RSA PRIVATE KEY----- [msie@bob rsa-example]$ openssl rsa -in private-1024.pem -pubout -out public.pem writing RSA key [msie@bib rsa-example]$ cat public.pem -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDG4QTKUK6WbYvnaY1tXcCtUmfO W2eTnldcgSq4/t+ZVsWU5wmDZcq6ncOGu8pkooyYQeReOuifSye6GMQudfD4ej9P KhDrH7gQcQJk2vV01ojPlYG5t5O6Coi7TvQy29waIOjThAqtg4H7Le4w0f4g0MJM lyOs3TKnz0qFx5jIqQIDAQAB -----END PUBLIC KEY----- # This will show the prime numbers p and q explicitly: [msie@bob rsa-example]$ openssl rsa -in private-1024.pem -text
Here's the recipe, as of OpenSSH_3.6.1p2, SSH protocols 1.5/2.0, OpenSSL 0x0090701f for logging in between two computers (call them "laptop.m.edu" and "remote.m.edu") without typing a password... see http://www.openssh.com/manual.html (Google "man openssh") First we create public/private keys on laptop.m.edu, which will be tied to the user and host given in in the shell environment variables. on laptop.m.edu : $ echo creating key for $LOGNAME@$HOSTNAME who@laptop.m.edu $ mkdir ~/.ssh/ $ cd ~/.ssh/ $ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/laptop/who/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /laptop/who/.ssh/id_rsa. Your public key has been saved in /laptop/who/.ssh/id_rsa.pub. The key fingerprint is: 7e:c6:f9:db:fc:38:4d:e9:73:82:e6:92:7b:59:c0:bd who@laptop.m.edu If a passphrase is given, then that phrase must be entered to gain access to the private key; this is less convenient but safer. Be clear that without a passphrase, anyone who can gain access to id_rsa can log into your remote accounts. Next, copy the public part of this into the file authorized_keys. If this is the only key you'll use, you can just do $ cp id_rsa.pub authorized_keys Finally, copy that authorized_keys file to the remote machine that you want to be able to log in to. $ scp authorized_keys who@remote.m.edu:.ssh/authorized_keys That's it. Now you should be able to do who@laptop$ ssh remote.m.edu who@remote$ without typing a password (!) Another way to do this to to encode your private key with a password but use an "agent" program to store it during your login session. With this approach, you need to type the passphrase once after you login to your laptop - then the running agent knows how to unlock your private key when it needs to. What's going on in any of these systems is that ssh uses your private key (in laptop:.ssh/id_rsa) to craft a message and send it to the remote machine. There it uses the corresponding public key in authorized_keys to see if you can get in. If it doesn't find one, then it asks for a password. The files look like this $ cat id_rsa -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDFEp7NPmh4WSXvPY0yrCEA5uVZmidIEZrH/0VOCp5ZITJCD9mc uqXu/ZYFtysiFSE5yTXsjz8UPcPbM6RHQnpyrTvVycg4yyeY+AKmCL1cLGsutWV+ s1M+wmUfBWUSgRKFopHDFxVerCUmJSMakW+pRpf9jVmOGYtdYyFilPZqWwIBIwKB gD3v6MQpjow5Rm/C4zvPspniKtMEkAC1E2NtfC54Xab7zfeBUwVfO3b/PcdIMiCn jhl5wH2MGyOeYiBSDw8U5KclZYlliIOZ/ZpxHCQ/5JfwVD/FZGGCXc/iekSCIvJK dCwmvuXRSNndCRuJG8y/aEXfYM//qel7is7Bt3JZk0f7AkEA7RaUNExJI7KOLXV3 C6ubFzc6FDkPX5W123ajiakbak1993jacklaiej1001kbGy22mqXBsRK+DXQFf/R VjXIuQJBANTK6YD4HmBlZTQcXo7dUgE/Kbi+fuN71oBhYKzrTivpAbddIB66WWgl RNK7KcP8/NP5XFkbisbKb818yFBJGbMCQQDfilE4n7KsoQm11ScZocy+HiDRPR0f m7ghx+1CCfgvGxUvA5Bu/uxnLbUKJIttixLN73h0GCltrxSnByR12vBzAkEAi9XM pTVVylFCgVR4pwZ3t60qC7BiAzQfPmvgcaHxipHN7YZW758HjZTVdImfGmRroT13 Mz38HDvjEgGK8u41dQJBAKKKfp8LJS0R9BOuF0oWxhFZR4QbySnSUCnQqYVG8rGY tgTLBzBtK0c9nYJEx9JEmY2SYg/fZiDiB3UN0Cb16/U= -----END RSA PRIVATE KEY----- $ cat id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAxRKezT5oeFkl7z2NMqwhAOblWZonSBGax/9FTgqeWSEyQg/Z nLql7v2WBbcrIhUhOck17I8/FD3D2zOkR0J6cq071cnIOMsnmPgCpgi9XCxrLrVlfrNTPsJlHwVlEoEShaKR wlJiUjGpFvqUaX/Y1ZjhmLXWMhYpT2als= who@laptop.m.edu
header : "Here's something from Alice, encoded with ...." MAC : RSA(AlicePrivateKey, RSA(BobPublicKey, "D,K,time")) Code : 3DES(K,M)
ssh server ssh -l user server # equivalently ssh user@server # lots of other flags available, e.g. ssh -d [debug level]; try ssh -h # escape from session with line-initial ~ (try ~?)
ssh server cmd
# an ftp-ish client sftp server # a cp-ish client scp from-file to-file # which takes various flags -p preserver attributes/timestamps, # -r recursive, either from-file or to-file may be remote; # file specification takes the form which allows for lovely # things like (from A as user u1): scp u2@B:foo/fup.html u3@C:
In all these respects, as we'll see, SSH resembles SSL. However there are important differences in the ways the two protocols operate. For example, in SSH the server is authenticated using public key cryptography, but this doesn't (yet) involve the use of X.509 certificates (the SSH v2 protocol allows for a server to pass a certificate to a client, but at this point all going implementations deal with the raw keys). Further, SSH has a much more extensive apparatus for dealing with client authentication than does SSL: in SSL, client authentication is optional and in practice rarely performed; when it is done, it amounts simply to a transfer of a digital certificate; SSH sessions, on the other hand, almost invariably include client authentication, and the protocol offers a number of modes of authentication.
uint32 packet_length byte padding_length byte[packet_length - padding_length - 1] payload byte[padding_length] padding byte[MAC_length] MAC (i.e., hash)
The various strings in the SSH_MSG_KEXINIT message consist of defined string constants for the various algorithms, comma-separated, and listed in decreasing order of preference. If both parties have the same algorithm in a given category ranked highest they use that; otherwise they use the algorithm most highly ranked by the client that the server knows how to do (and that's consistent with other algorithms selected). So here's what the initial offer looks like:
byte SSH_MSG_KEXINIT byte[16] cookie (random bytes) string kex_algorithms string encryption_algorithms_client_to_server string encryption_algorithms_server_to_client string mac_algorithms_client_to_server string mac_algorithms_server_to_client string compression_algorithms_client_to_server string compression_algorithms_server_to_client string languages_client_to_server string languages_server_to_client boolean first_kex_packet_follows uint32 reserved
byte SSH_MSG_KEXDH_INIT mpint e (= g**x mod p)
byte SSH_MSG_KEXDH_REPLY string K_S (this is the pub key) mpint f string s
At this point the session can move in various directions. Most commonly the client will request an operation involving one of the other sub-protocols--and most commonly of all will move to client authentication. The form of this request is
byte SSH_MSG_SERVICE_REQUEST string service name ("ssh-userauth" | "ssh-connection")If the server's prepared to proceed, it responds with a SSH_MSG_SERVICE_ACCEPT.
IdKey id_dsa_1024_a...where id_dsa_1024_a is the name of the file holding the private key. A copy of the public key is moved to the user's account on the server (under ~/.ssh2 again), and pointed to from ~/.ssh2/authorization with an entry of the form
Key id_dsa_1024_a.pub
Observe that there are some subtleties here--for example the client hashes the decrypted challenge (rather than returning it as is) to avoid the possibility that the challenge was actually something cleverly but maliciously chosen by the server--e.g. the (henceforth non-repudiable) plaintext "I hereby bequeath all my worldly possessions to the owner of server S", or perhaps a message previously encrypted with the user's public key
Let's say you're on A and you'd like to access a POP server on B--you'd like to, but you're worried about your POP username and password going in plaintext over the network. Let's say also that SSH facilities exist on both A and B. What port forwarding lets you do is to pass the POP connection through the SSH one. Three things are required:
ssh -L 7773:localhost:111 B...where -L mean "I want local forwarding" (vs. -R, "I want remote forwarding", which we'll get to in a second), and where the triple "7773:localhost:111" indicates a local entry point for an application client, the service provider (n.b. "localhost" here doesn't mean A, the machine initiating the SSH connection, rather it's relative to B, the machine receiving it), and the relevant port on the service provider, then what gets set up is the following arrangement (TCP ports are bracketed; we have a couple well-known server ports, 22 and 111, the listening port for the SSH client, as specified on the command line, and a couple other dynamic ports, for which I've picked numbers out of thin air)
This command still creates an ssh session on B, just as it would without the -L flag. It just has a side effect as well - the two ends of the connection listen for local connections on their respective computers, and pass that stuff back and forth as well.
The result is that on A, "telnet localhost 7773" will actually ring port 111 on B.
ssh -R 15658:localhost:80 D...your client will
The answer turns out to be no, by default, but this can be overridden. By default, the application client has to be on the same machine as the SSH client. The way this is enforced has to do with the way network sockets are allocated. When you say "gimme TCP port 7773", by default a socket is "bound", for that port, on all your machine's network interfaces. It possible however to restrict that binding, and that's what's done in the case of port forwarding--you get the port, but it's only on the (machine-internal) "loopback" interface associated with the IP address 127.0.0.1. This means that someone trying to reach this port will have to be able to do so at the destination address 127.0.0.1--and only another process on the same machine can do that.
The default behavior can be overridden in a user's config file (~/.ssh2/ssh2_config) with an entry like
GatewayPorts yesWith such an entry in place, the application client and SSH client can communicate over any IP link
ssh -L 7773:localhost:111 B..."localhost" tells B that the destination server is on B itself, at port 111. But we can insert any destination we like here. For example
ssh -L 7773:www.pardons-r-us.com:80 Bmeans
ssh -L 5159:L:111 K...and point your local mail client at 5159
On PM-firewall:
This example is artificial and restricted in a number of ways--starting with the face that in the case of web service you'd probably just run an SSL-based server at the home end, together with some form of client authentication. But there are other services, and the overall setup is in any case instructive.
Observe that
Client | Server |
SYN | |
SYN + ACK of client SYN | |
ACK of server SYN | |
Handshake:ClientHello
|
|
Handshake:ServerHello (contains essentially the same fields as the ClientHello
message. Server fills in session_id, for uses we'll see shortly. What's in cipher_suite
are the algorithms the client and server will actually use--i.e., the server decides) Handshake:Certificate (here's my X.509 certificate; see the example below) Handshake:ServerHelloDone |
|
Handshake:ClientKeyExchange (client selects pre_master_secret (= two bytes
designating version + 46 bytes of random, encrypts with sender's public key
(having verified the server's certificate and extracted the key) and sends;
each side now turns the pre_master_secret into the master_secret, and then to
turn the master_secret into a set of session keys; see below for further
details) ChangeCipherSpec (my next message will use the encryptions we agreed on) Handshake:Finished
|
|
ChangeCipherSpec (my next message will use the encryptions we agreed on) Handshake:Finished (here's a digest of what I just said) |
|
ApplicationData (blah blah blah) | |
ApplicationData (yak yak yak) | |
Alert: warning, close_notify (the point of which is to prevent
truncation attack, i.e., attacker inserting a premature FIN (they can't insert
a bogus close_notify because of the integrity checks built into SSL FIN |
|
Alert: warning, close_notify ACK of FIN FIN | |
ACK of FIN |
[root@at ssl.crt]# openssl x509 -noout -text -in server.crt Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: md5WithRSAEncryption Issuer: C=XY, ST=Snake Desert, L=Snake Town, O=Snake Oil, Ltd, OU=Certif icate Authority, CN=Snake Oil CA/Email=ca@snakeoil.dom Validity Not Before: Feb 14 19:03:52 2001 GMT Not After : Feb 14 19:03:52 2002 GMT Subject: C=XY, ST=Snake Desert, L=Snake Town, O=Snake Oil, Ltd, OU=Webse rver Team, CN=at.marlboro.edu/Email=root@at.marlboro.edu Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public Key: (1024 bit) Modulus (1024 bit): 00:c1:b1:97:57:c8:ed:cc:2f:aa:c7:6e:42:db:24: 99:d4:67:9c:d7:6a:f3:6d:cb:37:54:ea:8e:20:8f: df:8f:97:75:12:da:91:d4:49:86:e4:fd:d8:a9:cf: ab:ad:c2:2e:53:84:bd:44:da:de:cf:85:aa:2a:ba: 0b:7e:41:b5:8c:c7:a4:f0:3b:ac:db:68:65:86:40: d0:08:86:14:21:d7:46:a6:2d:e8:18:97:59:11:60: 1d:96:c2:cc:d5:91:48:ee:a1:a2:d7:c9:8d:9f:92: 96:b4:d0:2f:a3:c3:4a:36:ed:c9:ce:09:c9:2a:53: 10:c7:55:56:b4:1f:17:73:d1 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: email:root@at.marlboro.edu Netscape Comment: mod_ssl generated test server certificate Netscape Cert Type: SSL Server Signature Algorithm: md5WithRSAEncryption 83:c3:af:99:8b:2e:21:5d:88:ee:c0:7b:4c:5d:89:83:25:37: 00:d9:3b:cd:04:6c:ad:b0:f2:99:86:dc:fb:73:eb:2a:0d:e8: 96:87:ba:ea:73:3b:04:5a:d4:07:75:e6:8f:93:cd:3b:f7:01: 8a:f9:5e:96:04:65:75:73:24:20:7a:23:89:f9:a8:e3:7f:85: b8:85:5b:5b:56:3f:be:c9:83:62:1f:37:95:80:10:5b:19:8a: 03:d0:60:cd:0d:66:91:c5:ba:f5:5a:65:99:6f:32:ec:7a:72: 7c:d4:aa:32:67:73:d1:1d:7f:eb:c1:be:c2:85:87:89:7f:90: ec:dc [root@at ssl.crt]#
data = encrypted (contents + MAC + padding-to-encryption-blocksize + padding-length-byte)
MAC = hmac_hash(mac_signing_secret, sequence_number + type + version + data_length + contents)
Client | Server |
ClientHello | |
ServerHello Certificate CertificateRequest ServerHelloDone |
|
Certificate ClientKeyExchange CertificateVerify (client signs something to verify its identity; why doesn't the server need to do this?) |
Note also that once you've done encryption, you can't do any compression - the signal should look random at that point. (The SSL protocol does include some provisions for doing compression first, but apparently no one uses them.)
For a point of comparison, here's the start of a simple
(non-SSL) HTTP request for a text file between a client and a server on the same LAN.
Notice that it take six packets and just over three ms from receipt of client SYN to the
point at which the server pushes the first data packet out the door (we're looking
at this from the point of view of tcpdump running on the server; with some of the
tcpdump output excised to preserve sanity):
# 1: client SYN
10:00:03.799212 mdhcp244.marlboro.edu.1071 > at.marlboro.edu.www: S
# 2: server SYN + ACK-of-client-SYN
10:00:03.799276 at.marlboro.edu.www > mdhcp244.marlboro.edu.1071: S
# 3: client ACK-of-server-SYN
10:00:03.800850 mdhcp244.marlboro.edu.1071 > at.marlboro.edu.www: . ack 1
# 4: client http request
10:00:03.801705 mdhcp244.marlboro.edu.1071 > at.marlboro.edu.www: P 1:296(295)
# 5: server ACK of request
10:00:03.801753 at.marlboro.edu.www > mdhcp244.marlboro.edu.1071: . ack 296
# 6: server's first data packet
10:00:03.802412 at.marlboro.edu.www > mdhcp244.marlboro.edu.1071: P 1:1449(1448) ack 296
*****PACKETS 1-3***** New TCP connection #1: mdhcp244.marlboro.edu(1081) <-> at.marlboro.edu(443) *****PACKET 4***** 1 1 0.0022 (0.0022) C>S SSLv2 compatible client hello Version 3.0 cipher suites SSL2_CK_RC4 SSL2_CK_RC4_EXPORT40 SSL2_CK_RC2 SSL2_CK_RC2_EXPORT40 SSL2_CK_DES SSL2_CK_3DES SSL_RSA_WITH_RC4_128_MD5 Unknown value 0xfeff SSL_RSA_WITH_3DES_EDE_CBC_SHA Unknown value 0xfefe SSL_RSA_WITH_DES_CBC_SHA SSL_RSA_EXPORT1024_WITH_RC4_56_SHA SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA SSL_RSA_EXPORT_WITH_RC4_40_MD5 SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 *****PACKET 5 = TCP overhead***** *****PACKET 6***** 1 2 0.0034 (0.0012) S>CV3.0(74) Handshake ServerHello Version 3.0 random[32]= 3a 91 44 35 a0 ef 3a 08 a5 31 6d 0c 41 88 32 51 28 af f9 d9 33 61 98 23 59 4a 0f 82 eb 2d b4 d0 session_id[32]= 5f 14 ec 6b d0 05 e8 31 f4 d5 fc ab 12 13 a2 4c fe 1e b5 02 61 69 47 ec 67 78 e3 24 37 bb b5 a7 cipherSuite SSL_RSA_WITH_RC4_128_MD5 compressionMethod NULL 1 3 0.0034 (0.0000) S>CV3.0(841) Handshake Certificate 1 4 0.0034 (0.0000) S>CV3.0(4) Handshake ServerHelloDone *****PACKET 7 = TCP overhead***** *****PACKET 8***** 1 5 0.0118 (0.0083) C>SV3.0(132) Handshake ClientKeyExchange EncryptedPreMasterSecret[128]= 67 ee bf 34 28 ff 1a 8f 1b dd d2 4c e1 8e 78 9e 57 24 45 1e a4 5b c9 02 53 ea 42 7f 1c d7 a9 d3 8f e2 03 ae b9 d8 00 8e e4 d9 c7 eb 03 b8 d9 6a ee 7c 3c bb 9e 88 57 fc 01 06 4b ef 78 cf c1 b9 5a 8e a4 c8 35 e2 37 ca bc 6b 79 ab be fd d6 43 dc a1 1d cf 24 bb b2 20 85 1e f1 f8 e8 62 96 63 52 c1 07 32 f2 cb 90 9f 59 4d a5 7f 40 32 ee 08 f9 ef 10 ce e0 e4 0a ca 4b d8 8a 24 9e e3 b1 65 *****PACKET 9 = TCP overhead***** *****PACKET 10***** 1 6 0.0229 (0.0110) C>SV3.0(1) ChangeCipherSpec 1 7 0.0229 (0.0000) C>SV3.0(56) Handshake *****PACKET 11***** 1 8 0.0267 (0.0038) S>CV3.0(1) ChangeCipherSpec 1 9 0.0267 (0.0000) S>CV3.0(56) Handshake *****PACKET 12***** 1 10 0.0298 (0.0030) C>SV3.0(310) application_data *****PACKET 13***** 1 11 0.0312 (0.0014) S>CV3.0(3004) application_data
Client Server 0.07 Write client_hello 0.15 Read client_hello 0.07 Write server_hello 0.20 Write certificate (three certs) 0.00 Write server_hello_done 0.05 Read server_hello 8.11 Read certificate (three verifies) 0.00 Read server_hello_done 2.54 Write client_key_exchange (of which 2.26 encrypt_premaster) 0.15 Write finished 31.02 Read client_key_exchange (of which 30.79 decrypt_premaster) 0.00 Read finished 0.12 Write finished 0.00 Read finished
If the proxy is part of a firewall and client access to the Internet has to pass through the proxy, the client can resort to a special HTTP request method, CONNECT: the client sends a CONNECT request to the proxy specifying the intended SSL server ("CONNECT www.secrets.com:443 HTTP/1.1"); the server opens a TCP connection to the server at 443 and also returns a HTTP 200 (= everything's ok) response to the client; and the client then opens an SSL negotiation--received by the proxy, but passed straight through to the true origin server
Notice that if the proxy is really part of a firewall--i.e., if it's part of some sort of filtering system--the CONNECT mechanism has the (un)fortunate consequence that the proxy administrator no longer really knows what's passing through the proxy--there'd be no way to tell that the encrypted application traffic was HTTP (as opposed to some other protocol; no way to tell even if outbound connections were limited to destination port 443, since we have no idea what other people are actually running at any given port); there'd be no way to tell that it was SSL traffic at all (of course if you looked at it and it was going to port 23 and looked like telnet traffic you'd be suspicious; but if it started with a reasonable facsimile of an (unencrypted) SSL handshake and then turned to Greek, it'd be nearly impossible to tell true SSL traffic from bogus)
Notice also that the proxy is well-situated for a man-in-the-middle attack. It could, if the client were careless enough to accept a wildcard certificate--terminate the client's SSL messages locally, replicate them to the server over a second SSL connection, and examine the client's plaintext transmissions between the two SSL pipes.
The way this is solved in more recent HTTP implementations is by the use of a special Host header that accompanies the HTTP request, where "GET /foo.html HTTP/1.0" followed by "Host: www.a.com" disambiguates which foo is at issue (of course, the web-serving software also needs to know to read the Host header...)
But this scheme doesn't work under SSL. It doesn't work because the SSL-based server hasn't seen the HTTP request at the point it needs to send a (domain-identifying) certificate: a client makes a TCP connection and then sends a ClientHello; the next thing the server needs to do is to return a Certificate message... but should it send the one for www.a.com or www.b.com? It has no clue, because the client still hasn't made an HTTP request. Solutions: