몇 달 전 SSL web server using NIO and the SSLEngine을 개발했습니다. GET 요청은 작은 POST 요청 (10KB 미만)처럼 훌륭하게 작동합니다. 그러나 POST보다 더 큰 POST를 실행하면 간혹 SSLException 예외가 발생합니다.SSLException : 잘못된 패딩 TLS 응용 프로그램 데이터의 래핑 해제
예를 들어, 작은 이미지 (~ 16KB)를 POST하면 응용 프로그램 데이터를 나타내는 3 개의 TLS 레코드를 볼 수 있습니다. 첫 번째는 HTTP 헤더이고 다른 두 개는 페이로드를 포함합니다.
이1: 613 bytes
2: 16341 bytes
3: 549 bytes
내 코드에서 나는 SSLEngine의이 /의 포장을 TLS 기록 (응용 프로그램 데이터)를 해독하기 위해 전화 : 여기에 패킷이 얼마나 작은 감각이다. SSLEngine은, 2 번째의 레코드의 랩을 해제하려고하면 (자) 자주 울립니다. 여기에 오류가 있습니다 :
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
...
다음은 오류를 발생시키는 코드입니다.
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;
}
SSLException가이 라인에서 발생합니다 :
SSLEngineResult serverResult = sslEngine.unwrap(tlsRecord, output);
이 오류는 산발적으로 발생합니다. 때로는 그것을보고, 가끔은 그렇지 않습니다. 종종 오류를보고 단순히 데이터를 다시 POST (예 : 브라우저 새로 고침)하면 모든 것이 잘 작동합니다 (오류 없음).
저는 SSL 전문가가 아니므로 문제를 디버깅하는 것이 가장 좋은 방법을 모르겠습니다. 나는 unwrap 메소드를 올바르게 호출하고 있다고 확신합니다. 두 번째 레코드가 어떻게 든 손상 되었습니까? 사이퍼가 바뀌었고 핸드 셰이크를 다시 시작해야합니까? 이 오류가 발생하면 어떻게해야합니까?
커플 다른 점 : 나는 썬/오라클 JDK 6와 함께 번들로 제공 자바 보안 소켓 확장 (JSSE)을 사용하고
- .
- 모바일 사파리, iOS 6에서이 오류가 많이 보입니다. FireFox에서이 문제가 거의 발생하지 않습니다.
미리 감사드립니다.
오리지널 포스트에 답변 해 주셔서 감사합니다. 문제가 무엇인지 발견했습니다 (허용 된 솔루션 참조). SSLEngine에 유효한 버퍼를 공급하는 한 본질적으로 네트워크를 읽거나, TLS 레코드를 파싱하는 등의 문제가 있다고 생각하지 않습니다. 최소한 내 유스 케이스에서는 잘 작동하는 것 같다. 도와 주셔서 다시 한 번 감사드립니다! – Peter
그게 뭐가 잘못되었는지는 어려운 방법입니다. 답안에서 알 수 있듯이 공식적으로 필요하지 않은 많은 추가 코드로 끝날 것입니다. 이 SSLSocketChanrl 구현은이 엿보기 및 파킹을 포함하지 않습니다. 지상의 구멍에서 TLS 프로토콜을 알지 못합니다. – EJP