Come risulta, credo che la cache della sessione TLS di Secure Transport sia la causa.
Ho anche posto la domanda on the apple developer forums e ho ricevuto una risposta da una persona Apple. Lui mi ha indicato questo Apple sample code readme dove si dice:
In fondo alla pila TLS su entrambi iOS e Mac OS X è un componente conosciuto come un trasporto sicuro. Secure Transport gestisce una cache di sessione TLS per processo. Quando ci si connette tramite TLS, la cache memorizza le informazioni sulla negoziazione TLS in modo che le connessioni successive possano connettersi più rapidamente. Il meccanismo on-the-wire è descritto nel link sottostante.
http://en.wikipedia.org/wiki/Transport_Layer_Security#Resumed_TLS_handshake
Questo presenta alcuni trucchi interessanti, soprattutto mentre si sta debug. Ad esempio, si consideri la seguente sequenza:
È possibile utilizzare la scheda Debug per impostare il server di convalida TLS su Disabilitato.
Connessione a un sito con un'identità autofirmata. La connessione ha esito positivo perché hai disabilitato la convalida del trust del server TLS. Aggiunge una voce alla cache della sessione TLS di Secure Transport.
Si utilizza la scheda Debug per impostare la Convalida del server TLS su Predefinito.
Si collega immediatamente allo stesso sito come nel passaggio 2. Ciò non dovrebbe riuscire, a causa della modifica nel criterio di convalida della fiducia del server, ma ha esito positivo perché non si riceve mai una richiesta NSURLAuthenticationMethodServerTrust. Sotto le copertine, Secure Transport ha ripreso la sessione TLS, il che significa che la sfida non salirà mai al livello.
D'altra parte, se si ritarda per 11 minuti tra i passaggi 3 e 4, le cose funzionano come previsto (beh, fallire come previsto :-). Questo perché la cache della sessione TLS di Secure Transport ha un timeout di 10 minuti.
Nel mondo reale questo non è un problema enorme, ma può essere molto confuso durante il debug. Non esiste un modo programmatico per svuotare la cache della sessione TLS di Secure Transport ma, poiché la cache è per processo, è possibile evitare questo problema durante il debug semplicemente abbandonando e rilanciando l'applicazione. Ricorda che, a partire da iOS 4, la pressione del pulsante Home non chiude necessariamente la tua applicazione. Invece, dovresti uscire dall'applicazione dall'elenco delle applicazioni recenti.
Quindi, in base a ciò, un utente dovrebbe o uccidere la propria app e riavviarlo o attendere più di 10 minuti prima di inviare un'altra richiesta.
Ho fatto un'altra ricerca su Google con questa nuova informazione e ho trovato this Apple technical Q&A article che corrisponde esattamente a questo problema. Vicino al fondo, si menziona l'aggiunta di un 'finale'. ai nomi di dominio (e, auspicabilmente, agli indirizzi IP) per le richieste al fine di forzare un errore nella cache della sessione TLS (se non riesci a modificare il server in qualche modo, cosa che non posso), quindi ho intenzione di provare questo e spero che sia funzionerà. Pubblicherò le mie scoperte dopo averlo testato.
### EDIT ###
ho provato l'aggiunta di un '' alla fine dell'indirizzo ip e la richiesta è stata ancora completata con successo.
Ma stavo pensando al problema in generale e non c'è davvero alcun motivo per forzare un altro handshake SSL. Nel mio caso, la soluzione a questo problema è di conservare una copia dell'ultimo SecCertificateRef noto che è stato restituito dal server. Quando si effettua un'altra richiesta al server, se viene utilizzata una sessione TLS memorizzata nella cache (non è stato chiamato connection:didReceiveAuthenticationChallenge:
), sappiamo che lo SecCertificateRef
salvato è ancora valido. Se si chiama connection:didReceiveAuthenticationChallenge:
, possiamo ottenere il nuovo SecCertificateRef
in quel momento.
Ho lo stesso problema. Ho provato diverse correzioni ma finora nessuno di loro ha funzionato. – EricS