Advertisement
Guest User

Untitled

a guest
Jun 11th, 2017
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.25 KB | None | 0 0
  1. --- ./Pop3Store.java.ORIG 2010-08-24 08:35:44.831443463 -0400
  2. +++ Pop3Store.java 2010-08-24 10:06:34.803443702 -0400
  3. @@ -11,13 +11,22 @@
  4. import com.fsck.k9.mail.Folder.OpenMode;
  5. import com.fsck.k9.mail.internet.MimeMessage;
  6.  
  7. +import org.apache.commons.codec.binary.Base64;
  8. +import org.apache.commons.codec.binary.Hex;
  9. +
  10. import javax.net.ssl.SSLContext;
  11. import javax.net.ssl.SSLException;
  12. import javax.net.ssl.TrustManager;
  13. import java.io.*;
  14. import java.net.*;
  15. +import java.nio.ByteBuffer;
  16. +import java.nio.CharBuffer;
  17. +import java.nio.charset.Charset;
  18. import java.security.GeneralSecurityException;
  19. +import java.security.MessageDigest;
  20. +import java.security.NoSuchAlgorithmException;
  21. import java.security.SecureRandom;
  22. +import java.security.Security;
  23. import java.util.ArrayList;
  24. import java.util.Date;
  25. import java.util.LinkedList;
  26. @@ -33,13 +42,19 @@
  27. public static final int CONNECTION_SECURITY_SSL_REQUIRED = 3;
  28. public static final int CONNECTION_SECURITY_SSL_OPTIONAL = 4;
  29.  
  30. + private enum AuthType { PLAIN, CRAM_MD5 };
  31. +
  32. private static final Flag[] PERMANENT_FLAGS = { Flag.DELETED };
  33.  
  34. + private static final String CAPABILITY_CAPABILITY = "CAPABILITY";
  35. + private static final String COMMAND_CAPABILITY = "CAPABILITY";
  36. +
  37. private String mHost;
  38. private int mPort;
  39. private String mUsername;
  40. private String mPassword;
  41. private int mConnectionSecurity;
  42. + private AuthType mAuthType;
  43. private HashMap<String, Folder> mFolders = new HashMap<String, Folder>();
  44. private Pop3Capabilities mCapabilities;
  45.  
  46. @@ -70,10 +85,10 @@
  47.  
  48. /**
  49. * pop3://user:password@server:port CONNECTION_SECURITY_NONE
  50. - * pop3+tls://user:password@server:port CONNECTION_SECURITY_TLS_OPTIONAL
  51. - * pop3+tls+://user:password@server:port CONNECTION_SECURITY_TLS_REQUIRED
  52. - * pop3+ssl+://user:password@server:port CONNECTION_SECURITY_SSL_REQUIRED
  53. - * pop3+ssl://user:password@server:port CONNECTION_SECURITY_SSL_OPTIONAL
  54. + * pop3+tls://auth:user:password@server:port CONNECTION_SECURITY_TLS_OPTIONAL
  55. + * pop3+tls+://auth:user:password@server:port CONNECTION_SECURITY_TLS_REQUIRED
  56. + * pop3+ssl+://auth:user:password@server:port CONNECTION_SECURITY_SSL_REQUIRED
  57. + * pop3+ssl://auth:user:password@server:port CONNECTION_SECURITY_SSL_OPTIONAL
  58. */
  59. public Pop3Store(Account account) throws MessagingException
  60. {
  61. @@ -132,11 +147,18 @@
  62. try
  63. {
  64. String[] userInfoParts = uri.getUserInfo().split(":");
  65. - mUsername = URLDecoder.decode(userInfoParts[0], "UTF-8");
  66. - if (userInfoParts.length > 1)
  67. + if (userInfoParts.length == 2)
  68. {
  69. + mAuthType = AuthType.PLAIN;
  70. + mUsername = URLDecoder.decode(userInfoParts[0], "UTF-8");
  71. mPassword = URLDecoder.decode(userInfoParts[1], "UTF-8");
  72. }
  73. + else
  74. + {
  75. + mAuthType = AuthType.valueOf(userInfoParts[0]);
  76. + mUsername = URLDecoder.decode(userInfoParts[1], "UTF-8");
  77. + mPassword = URLDecoder.decode(userInfoParts[2], "UTF-8");
  78. + }
  79. }
  80. catch (UnsupportedEncodingException enc)
  81. {
  82. @@ -197,7 +219,7 @@
  83. private HashMap<Integer, Pop3Message> mMsgNumToMsgMap = new HashMap<Integer, Pop3Message>();
  84. private HashMap<String, Integer> mUidToMsgNumMap = new HashMap<String, Integer>();
  85. private String mName;
  86. - private int mMessageCount;
  87. + protected volatile int mMessageCount;
  88.  
  89. public Pop3Folder(String name)
  90. {
  91. @@ -217,6 +239,8 @@
  92. return;
  93. }
  94.  
  95. + boolean authSuccess = false;
  96. +
  97. if (!mName.equalsIgnoreCase("INBOX"))
  98. {
  99. throw new MessagingException("Folder does not exist");
  100. @@ -289,8 +313,26 @@
  101.  
  102. try
  103. {
  104. - executeSimpleCommand("USER " + mUsername);
  105. - executeSimpleCommand("PASS " + mPassword, true);
  106. + if (mAuthType == AuthType.CRAM_MD5)
  107. + {
  108. + authCramMD5();
  109. + // The authCramMD5 method called on the previous line does not allow for handling updated capabilities
  110. + // sent by the server. So, to make sure we update to the post-authentication capability list
  111. + // we fetch the capabilities here.
  112. + if (K9.DEBUG)
  113. + Log.i(K9.LOG_TAG, "Updating capabilities after CRAM-MD5 authentication for " + getLogId());
  114. + List<ImapResponse> responses = receiveCapabilities(executeSimpleCommand(COMMAND_CAPABILITY));
  115. + if (responses.size() != 2)
  116. + {
  117. + throw new MessagingException("Invalid CAPABILITY response received");
  118. + }
  119. +
  120. + }
  121. + else if (mAuthType == AuthType.PLAIN)
  122. + {
  123. + receiveCapabilities(executeSimpleCommand("LOGIN \"" + escapeString(mUsername) + "\" \"" + escapeString(mPassword) + "\"", true));
  124. + }
  125. + authSuccess = true;
  126. }
  127. catch (MessagingException me)
  128. {
  129. @@ -312,14 +354,109 @@
  130. {
  131. throw new MessagingException("Unable to open connection to POP server.", ioe);
  132. }
  133. + }
  134. + finally
  135. + {
  136. + if (authSuccess == true)
  137. + {
  138. + String response = executeSimpleCommand("STAT");
  139. + String[] parts = response.split(" ");
  140. + mMessageCount = Integer.parseInt(parts[1]);
  141. +
  142. + mUidToMsgMap.clear();
  143. + mMsgNumToMsgMap.clear();
  144. + mUidToMsgNumMap.clear();
  145. + }
  146. + else
  147. + }
  148. + Log.e(K9.LOG_TAG, "Failed to login, closing connection for " + getLogId());
  149. + close();
  150. + }
  151. + }
  152. + }
  153.  
  154. - String response = executeSimpleCommand("STAT");
  155. - String[] parts = response.split(" ");
  156. - mMessageCount = Integer.parseInt(parts[1]);
  157. -
  158. - mUidToMsgMap.clear();
  159. - mMsgNumToMsgMap.clear();
  160. - mUidToMsgNumMap.clear();
  161. + protected void authCramMD5() throws AuthenticationFailedException, MessagingException
  162. + {
  163. + try
  164. + {
  165. + String tag = sendCommand("AUTHENTICATE CRAM-MD5", false);
  166. + byte[] buf = new byte[ 1024 ];
  167. + int b64NonceLen = 0;
  168. + for (int i = 0; i < buf.length; i++)
  169. + {
  170. + buf[ i ] = (byte)mIn.read();
  171. + if (buf[i] == 0x0a)
  172. + {
  173. + b64NonceLen = i;
  174. + break;
  175. + }
  176. + }
  177. + if (b64NonceLen == 0)
  178. + {
  179. + throw new AuthenticationFailedException("Error negotiating CRAM-MD5: nonce too long.");
  180. + }
  181. + byte[] b64NonceTrim = new byte[ b64NonceLen - 2 ];
  182. + System.arraycopy(buf, 1, b64NonceTrim, 0, b64NonceLen - 2);
  183. + byte[] nonce = Base64.decodeBase64(b64NonceTrim);
  184. + if (K9.DEBUG)
  185. + {
  186. + Log.d(K9.LOG_TAG, "Got nonce: " + new String(b64NonceTrim, "US-ASCII"));
  187. + Log.d(K9.LOG_TAG, "Plaintext nonce: " + new String(nonce, "US-ASCII"));
  188. + }
  189. +
  190. + byte[] ipad = new byte[64];
  191. + byte[] opad = new byte[64];
  192. + byte[] secretBytes = mPassword.getBytes("US-ASCII");
  193. + MessageDigest md = MessageDigest.getInstance("MD5");
  194. + if (secretBytes.length > 64)
  195. + {
  196. + secretBytes = md.digest(secretBytes);
  197. + }
  198. + System.arraycopy(secretBytes, 0, ipad, 0, secretBytes.length);
  199. + System.arraycopy(secretBytes, 0, opad, 0, secretBytes.length);
  200. + for (int i = 0; i < ipad.length; i++) ipad[i] ^= 0x36;
  201. + for (int i = 0; i < opad.length; i++) opad[i] ^= 0x5c;
  202. + md.update(ipad);
  203. + byte[] firstPass = md.digest(nonce);
  204. + md.update(opad);
  205. + byte[] result = md.digest(firstPass);
  206. + String plainCRAM = mUsername + " " + new String(Hex.encodeHex(result));
  207. + byte[] b64CRAM = Base64.encodeBase64(plainCRAM.getBytes("US-ASCII"));
  208. + if (K9.DEBUG)
  209. + {
  210. + Log.d(K9.LOG_TAG, "Username == " + mUsername);
  211. + Log.d(K9.LOG_TAG, "plainCRAM: " + plainCRAM);
  212. + Log.d(K9.LOG_TAG, "b64CRAM: " + new String(b64CRAM, "US-ASCII"));
  213. + }
  214. +
  215. + mOut.write(b64CRAM);
  216. + mOut.write(new byte[] { 0x0d, 0x0a });
  217. + mOut.flush();
  218. + int respLen = 0;
  219. + for (int i = 0; i < buf.length; i++)
  220. + {
  221. + buf[ i ] = (byte)mIn.read();
  222. + if (buf[i] == 0x0a)
  223. + {
  224. + respLen = i;
  225. + break;
  226. + }
  227. + }
  228. + String toMatch = tag + " OK";
  229. + String respStr = new String(buf, 0, respLen);
  230. + if (!respStr.startsWith(toMatch))
  231. + {
  232. + throw new AuthenticationFailedException("CRAM-MD5 error: " + respStr);
  233. + }
  234. + }
  235. + catch (IOException ioe)
  236. + {
  237. + throw new AuthenticationFailedException("CRAM-MD5 Auth Failed.");
  238. + }
  239. + catch (NoSuchAlgorithmException nsae)
  240. + {
  241. + throw new AuthenticationFailedException("MD5 Not Available.");
  242. + }
  243. }
  244.  
  245. @Override
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement