Secure channel ============= Secure channel TCP/IP doesn't provide authenticity and confidentiality Using crypto we layer a secure channel on top of TCP/IP Case study: TLS/SSL Secure channels are strong foundation for security Run HTTP over SSL and Web is "secure" Slowly becoming the default Run SMTP over SSL and mail delivery is "secure" Run IMAP/POP over SSL and mail pickup is "secure" Etc. Well understood/developed area of security Cryptography is a powerful security mechanism Encryption: confidentiality Signatures: integrity Public-key vs private-key (also called symmetric-key) Public key operations: KeyGen() -> public key PK, secret key SK Encrypt(PK, message m) -> ciphertext c Decrypt(SK, c) -> m or Sign(SK, m) -> signature sig Verify(PK, m, sig) -> ok? Private key operations: KeyGen() -> private (symmetric) key K Encrypt(K, m) -> c Decrypt(K, c) -> m or MAC(K, m) -> tag t (Keys for MAC and encryption should be different. If you need both encryption and MAC, you need two keys.) Establishing a secure channel Goal: establish a shared key for symmetric crypto Strawman: C --> S: connect C <-- S: my public key is PK_S C --> S: Encrypt(PK_S, freshKey) C <-> S: Encrypt(freshKey, m...) Problem 1: authenticating the server What if an adversary intercepts messages to the server? Client's view is exactly the same Client will have a shared key with the adversary Adversary can connect to real server and relay messages Subsequent messages appear to be just fine "Man-in-the-middle attack" Need to bind PK_S to server's identity (principal name) Solution: certificates Trusted authority server Maintains table of (principal name, public key) pairs Principal name is typically the server's DNS name Choice of name must capture the client's intended communication target Crucial that the name is correct! Need to worry about typos, look-alikes Other participants rely on authority server to have the right mapping Need to know the authority server's public key to bootstrap all this More on certificates in next week's lecture Could query server, but that's bad for availability, performance Instead, authority server can sign a message: Sign(SK_CA, {server, PK_server}) This is the server's "certificate" Server can send this certificate to the client Client can verify that it's correctly signed by PK_CA Adversary would not be able to provide such a certificate for adversary's PK_S Revised strawman protocol: C --> S: connect C <-- S: PK_S, Sign(SK_CA, {server: PK_S}) C --> S: Encrypt(PK_S, freshKey) C <-> S: Encrypt(freshKey, m...) Alternative solution: trust-on-first-use (TOFU), as in SSH Assume first connection is OK Remember binding between PK_S and server's principal name for future use Easier to deploy, fewer security properties Problem 2: authenticating the messages C <-> S: Encrypt(freshKey, m...) Suppose client sends request "Transfer $1 to Bob's account" Encryption guarantees confidentiality but not integrity One way to think of it: Decrypt() always succeeds Adversary tampers with ciphertext -> Decrypt will return something else Sometimes predictable effects: flip ciphertext bit -> flip message bit Note that this does not break confidentiality In our example: flip a bit to send $129 to Bob Solution: use MAC() to compute an authentication tag C <-> S: c=Encrypt(freshKey1, m...), t=MAC(freshKey2, c) [ Note: important to use different keys for Encrypt and MAC ] This is called "Authenticated encryption" Tag will be incorrect: message rejected after tampering What if adversary retransmits the messages? Doesn't tamper with message but just sends it 129 times From server's perspective: 129 valid messages Need to defend against replay attacks Solution: keep track of previously seen messages Discard messages that have already been processed Two common approaches: 1. Sequence number in message Receiver tracks last-seen sequence number Discard messages with older sequence numbers Good for stream-oriented protocols 2. Expiration / session ID in message Receiver tracks ALL past messages within expiration time or within session Discard previously received messages Good for message-oriented (non-stream) protocols Problem 3: future server breakin What if a bad guy later compromises the server? Can use SK_S to decrypt old network packets This in turn reveals the freshKey value for old traffic Can decrypt old traffic contents! Solution: forward secrecy Don't use long-term keys for encryption Susceptible to decryption by a future adversary Instead, use short-lived keys for encryption, and long-term keys for signing Future adversary can forge signatures in the future, but it's too late Strawman forward secrecy for our protocol: C --> S: connect C <-- S: PK_conn, Sign(SK_CA, {server: PK_S}), Sign(SK_S, PK_conn) C --> S: Encrypt(PK_conn, freshKey) C <-> S: Encrypt(freshKey, m...) S uses SK_conn to get freshKey and then throws it away. SSL/TLS The secure channel protocol for the Web SSL originally defined by Netscape TLS is the international standard version Improvements over the years SSL 2.0, SSL 3.0 (1996), TLS 1.0 (1999), TLS 1.1 (2006), TLS 1.2 (2008), TLS 1.3 (2018) SSL 2: https://www-archive.mozilla.org/projects/security/pki/nss/ssl/draft02.html SSL 3: https://paulkocher.com/doc/SSLv3.pdf https://en.wikipedia.org/wiki/Transport_Layer_Security SSL 3.0 is now "forbidden" Protocol uses block ciphers incorrectly (CBC) Or uses weak stream cipher (RC4) Main parts to it Record protocol (send/receiving messages) Handshake protocol (setting up keys to authenticate/encrypt messages) Analysis: threat models Active attackers tamper and forge messages Passive attackers only eavesdropping e.g., traffic analysis SSL (especially with a stream cipher) ciphertext length reveals plaintext length allows attacker to learn which web page was accessed can learn which computers are communicating SSL 3.0 handshake (simplified) 1. C -> S: Hello: client version, randomC, session_id, ciphers 2. S -> C: Hello: server version, randomS, session_id, ciphers 3. S -> C: ServerCertificate: cert list 4. S -> C: HelloDone [[ client picks random pre_master_secret ]] 5. C -> S: ClientKeyExchange: encrypt (pre_master_secret, PK_S) 6. C -> S: ChangeCipherSpec 7. C -> S: finished, MAC({master_secret ++ msg 1,2,3,4,5}, C_mac_key) (and encrypted) 8. S -> C: change cipher spec 9. S -> C: finished, MAC({master_secret ++ msg 1,2,3,4,5,7}, S_mac_key) (and encrypted) 10. C -> S: encrypt({data, MAC(data, C_mac_key)}, C_enc_key) master_secret <- PRF(pre_master_secret, "master secret", randomC+randomS) (C_mac_key, C_enc_key) <- PRF(master_secret, "key expansion", randomS+randomC) SSL 2.0 attack Adversary could edit ClientHello message undetected Tell S to substitute strong ciphers with weak ciphers SSL 3.0 risk: version roll-back attack Adversary modifies ClientHello to be say version 2 Client adds "marker" in authenticated padding bytes Works only with RSA key-exchange SSL 3.0 attack: drop ChangeCipher MAC doesn't include message 6 and 8 attacker delete 6 and 8 Client and server won't switch to using ciphers! Attacker can change data to S TLS 1.0: Finish must be preceded by ChangeCipher SSL 3.0: POODLE (Oct 2014) MAC doesn't cover block-cipher padding Can be used to guess cookie in small number of tries Normal operation: encryption: Ci = E(K, Mi) xor Ci-1 That is Cipher Block Chaining (CBC), E = AES C0 = a random initialization vector decryption: Mi = D(K, Ci) xor Ci-1 in SSL msg format: msg || 20-byte MAC || padding last byte of last block records number of padding bytes other bytes in padding are not specified, anything is ok MAC doesn't cover padding! receiver: decrypt blocks, remove padding, re-compute MAC, checks MAC, removes MAC Attacker: 1. Get user to run some javascript that sends post to web site user is using POST /path Cookie: name=\r\n\r\nbody || 20-byte MAC || padding Attacker's javascript can access cookie, but browser will send it 2. Attacker interposes on traffic between client and web site a. Attacker sees encrypted version of above message, but attacker can arrange for: - a full block of padding P - Ci to have the first-to-guess byte of cookie to be in last byte b. copy Ci into P if server accepts message, then - D(K, Ci)[15] xor Cn-1[15] = 15 We know D(K, Ci)[15] = Mi[15] xor Ci-1[15] => Mi[15] = 15 xor Cn-1[15] xor Ci-1[15] - attacker moves to next byte of cookie if server rejects message, connection is closed - retry post on a new connection different IV/key - with 256 tries, we should get lucky See https://www.openssl.org/~bodo/ssl-poodle.pdf for full details Or, https://www.imperialviolet.org/2014/10/14/poodle.html Observation: protocol bug; not implementation bug SSL3.0 is forbidden now TLS doesn't allow the padding bytes to be unspecified Be explicit/Horton Principle The Horton quote is "I meant what I said and I said what I meant", which the authors adopted for protocol design Design principle, helpful in analyzing protocols Every message must be explicit on the context that it depends on Finish message in SSL3.0 is not explicit about message 6 Security is also dependent on the implementation SSL/TLS is complicated, thus implementation bugs TLS 1.3 simpler than 1.2! Popular implementation: openSSL Heartbleed bug in 2014 Adversary can steal private key Buffer overrun bug --- made it to here --- Who can access encrypted data? Secure channels protect against an adversary that controls the network Data available as plaintext on either end of the secure channel Compromised server can get access to the data: server has decryption key Alternative: do not give server the decryption key End-to-end encryption / encryption at rest Data encrypted with a key of the intended app-level recipient Not necessarily the server that transmits or stores the message E.g., text messaging: encrypt with other user's key Server stores and forwards ciphertext, cannot look inside Recipient can eventually decrypt message E.g., file storage: encrypt with user's own key Server stores encrypted data, cannot look inside User can download file back from the server, decrypt it Lab 5 Powerful: cuts out worrying about attacks on server (w.r.t. confidentiality) Shared encrypted data: how to give multiple users access to shared doc? Naive plan: encrypt same document with each user's key. Downside: multiple copies, possibly diverging versions. Better plan: chaining keys. Generate a new key just for the document. Encrypt document with the document's public key. Encrypt document's secret key with each user's public key. References Attack by Rizzo and Duong can allow adversary to learn some plaintext by issuing many carefully-chosen requests over a single connection. [ Ref: http://www.educatedguesswork.org/2011/09/security_impact_of_the_rizzodu.html ] Recent attack by same people using compression, mentioned in Paul Youn's lecture. [ Ref: http://en.wikipedia.org/wiki/CRIME ] Most recently, more padding oracle attacks. [ Ref: https://www.openssl.org/~bodo/ssl-poodle.pdf ] Some servers/CAs use weak crypto, e.g. certificates using MD5. Some clients choose weak crypto (e.g., SSL/TLS on Android). [ Ref: http://op-co.de/blog/posts/android_ssl_downgrade/ ] Some implementations use bad randomness to generate keys [ Ref: https://wiki.debian.org/SSLkeys#End_User_Summary ] But, cryptography is rarely the weakest part of a system. RSA versus DH handshake https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/ Illustrated TLS 1.3 handshake [ Ref: https://tls13.ulfheim.net/ ]