title: SSLException: Invalid padding Unwrapping TLS Application Data
body: <p>Several months ago I developed an <a href="https://stackoverflow.com/questions/9604532/ssl-handshaking-using-self-signed-certs-and-sslengine-jsse">SSL web server using NIO and the SSLEngine</a>. GET requests work great as do small POST requests (under ~10KB). However, I'm getting sporadic SSLException exceptions, when I POST anything larger than that. </p>
  
  <p>For example, if I POST a small image (~16KB), I can see 3 TLS records representing application data. The first is the HTTP header, and the other two contain the payload. Here's a sense of how small the packets are:</p>
  
  <pre><code>1: 613 bytes
  2: 16341 bytes
  3: 549 bytes
  </code></pre>
  
  <p>In my code, I call the SSLEngine to unwrap/decrypt the TLS records (application data). Frequently, the SSLEngine chokes when it tries to unwrap the second record. Here's the error:</p>
  
  <pre><code>javax.net.ssl.SSLException: Invalid padding
      at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source)
      at com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(Unknown Source)
      at com.sun.net.ssl.internal.ssl.SSLEngineImpl.readRecord(Unknown Source)
      at com.sun.net.ssl.internal.ssl.SSLEngineImpl.readNetRecord(Unknown Source)
      at com.sun.net.ssl.internal.ssl.SSLEngineImpl.unwrap(Unknown Source)
      at javax.net.ssl.SSLEngine.unwrap(Unknown Source)
      at javaxt.http.servlet.HttpServletRequest.getApplicationData(HttpServletRequest.java:1793)
      ...
  
      Caused by: javax.crypto.BadPaddingException: Invalid TLS padding: 199
      ...
  </code></pre>
  
  <p>Here's the code that's throwing the error. </p>
  
  <pre><code>private byte[] getApplicationData() throws IOException {
  
    //Read the next 5 bytes from the socket channel. This should contain TLS
    //record information.
      if (recordHeader==null){
          recordHeader = ByteBuffer.allocateDirect(5);
          read(recordHeader);
      }
  
    //Verify that the message contains application data
      recordHeader.rewind();
      if(recordHeader.get()!=23) throw new IOException();
  
    //Get the length of the TLS record
      recordHeader.position(3);
      int recordLength = Integer.parseInt(getHex(recordHeader) + getHex(recordHeader), 16);
      recordHeader.rewind();
  
    //Read the TLS record
      ByteBuffer recordData = ByteBuffer.allocateDirect(recordLength);
      read(recordData);
      recordData.rewind();
  
    //Merge the TLS header and record data into a single buffer
      ByteBuffer tlsRecord = ByteBuffer.allocateDirect(recordLength+recordHeader.capacity());
      tlsRecord.put(recordHeader);
      tlsRecord.put(recordData);
      tlsRecord.rewind();
  
    //Decrypt the application data
      ByteBuffer output = ByteBuffer.allocateDirect(tlsRecord.capacity());
      SSLEngineResult serverResult = sslEngine.unwrap(tlsRecord, output);
      runDelegatedTasks(serverResult, sslEngine);
  
  
      byte[] arr = new byte[output.position()];
      output.rewind();
      output.get(arr);
  
  
    //Clean up
      recordHeader.clear();
      recordData.clear();
      tlsRecord.clear();
      output.clear();
      recordHeader = recordData = tlsRecord = output = null;
  
  
    //Return array
      return arr;
  }
  </code></pre>
  
  <p>The SSLException is thrown at this line:</p>
  
  <pre><code>SSLEngineResult serverResult = sslEngine.unwrap(tlsRecord, output);
  </code></pre>
  
  <p>This error occurs sporadically. Sometimes I see it, sometimes I don't. Oftentimes, if I do see the error and simply re-POST the data (e.g. refresh the browser), everything works great (no errors).</p>
  
  <p>I am not an SSL expert by any means so I don't know how best to debug the issue. I'm pretty sure I'm calling the unwrap method correctly. Is the second record somehow corrupt? Has the cypher changed and I need to re-initiate a handshake? What do I do when I encounter this error? </p>
  
  <p>Couple other points:</p>
  
  <ul>
  <li>I'm using Sun/Oracle JDK 6 and Java Secure Socket Extension (JSSE) that comes bundled with it.</li>
  <li>I'm seeing this error a lot when with Mobile Safari, iOS 6. I rarely have this issue with FireFox.</li>
  </ul>
  
  <p>Thanks in advance!</p>