Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CryptoUpcalls: Exception while decrypting message with RSA private key using RSA/ECB/PKCS1Padding #15

Open
ghost opened this issue Mar 30, 2021 · 8 comments

Comments

@ghost
Copy link

ghost commented Mar 30, 2021

Ho un android 10 dove l'app CieID fallisce l'autenticazione, così ho provato questa libreria che usa lo stesso codice dell'app.
Sto provando l'autenticazione su sito inps flusso interno, quindi niente app cieid. L'url configurata è questa https://www.inps.it/myinps/default.aspx?accessoinps=1
Ho disabilitato il Pinning dei certificati per evitare problemi, ma comunque non è li l'errore. Quando viene richiesto di fare il sign dei byte ricevuti dal sito idserver.servizicie.interno.gov.it, la CIE risponde con un 6882 (Secure messaging not supported).
L'autenticazione alla carta va a buon fine, perchè riesco a leggere e salvare il certificato pubblico in formato BER.
Di seguito l'eccezione:

03-30 13:08:06.918 12622 12878 I okhttp.OkHttpClient: --> POST https://idserver.servizicie.interno.gov.it/idp/Authn/SSL/Login2
03-30 13:08:06.919 12622 12878 I okhttp.OkHttpClient: Content-Type: application/x-www-form-urlencoded
03-30 13:08:06.921 12622 12878 I okhttp.OkHttpClient: Content-Length: 88
03-30 13:08:06.921 12622 12878 I okhttp.OkHttpClient: User-Agent: Mozilla/5.0
03-30 13:08:06.924 12622 12878 I okhttp.OkHttpClient: generaCodice=1&authnRequest=_AUTH-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX&conversation=XXXX
03-30 13:08:06.924 12622 12878 I okhttp.OkHttpClient: --> END POST (88-byte body)
03-30 13:08:07.415 12622 12878 D CieIDSdkLogger: sign()
03-30 13:08:07.434 12622 12878 D CieIDSdkLogger: APDU: 0C2241A415870901XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
03-30 13:08:07.505 12622 12878 D CieIDSdkLogger: RESPONSE: 
03-30 13:08:07.506 12622 12878 D CieIDSdkLogger: SW: 6882
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: Exception while decrypting message with RSA private key using RSA/ECB/PKCS1Padding:
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at it.ipzs.cieidsdk.nfc.Ias.respSM(Ias.kt:1523)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at it.ipzs.cieidsdk.nfc.Ias.getRespSM(Ias.kt:1630)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at it.ipzs.cieidsdk.nfc.Ias.sendApduSM(Ias.kt:1364)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at it.ipzs.cieidsdk.nfc.Ias.sign(Ias.kt:638)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at it.ipzs.cieidsdk.ciekeystore.Cipher.engineDoFinal(Cipher.kt:30)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at javax.crypto.Cipher.doFinal(Cipher.java:2055)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at com.android.org.conscrypt.CryptoUpcalls.rsaOpWithPrivateKey(CryptoUpcalls.java:214)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at com.android.org.conscrypt.CryptoUpcalls.rsaSignDigestWithPrivateKey(CryptoUpcalls.java:132)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at com.android.org.conscrypt.NativeCrypto.SSL_read(Native Method)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at com.android.org.conscrypt.NativeSsl.read(NativeSsl.java:411)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLInputStream.read(ConscryptFileDescriptorSocket.java:549)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okio.InputStreamSource.read(JvmOkio.kt:90)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:129)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okio.RealBufferedSource.indexOf(RealBufferedSource.kt:427)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.kt:320)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http1.HeadersReader.readLine(HeadersReader.kt:29)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http1.Http1ExchangeCodec.readResponseHeaders(Http1ExchangeCodec.kt:178)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.connection.Exchange.readResponseHeaders(Exchange.kt:106)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:79)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:34)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.kt:221)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at retrofit2.OkHttpCall.execute(OkHttpCall.java:204)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:46)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at io.reactivex.Observable.subscribe(Observable.java:12284)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at io.reactivex.internal.operators.observable.ObservableSingleSingle.subscribeActual(ObservableSingleSingle.java:35)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at io.reactivex.Single.subscribe(Single.java:3666)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
03-30 13:08:07.514 12622 12878 W CryptoUpcalls: 	at java.lang.Thread.run(Thread.java:919)
03-30 13:08:07.520 12622 12878 I okhttp.OkHttpClient: <-- HTTP FAILED: javax.net.ssl.SSLProtocolException: Read error: ssl=0x79fcd54208: Failure in SSL library, usually a protocol error
03-30 13:08:07.520 12622 12878 I okhttp.OkHttpClient: error:04000044:RSA routines:OPENSSL_internal:internal error (external/conscrypt/common/src/jni/main/cpp/conscrypt/native_crypto.cc:740 0x7a4cedce6b:0x00000000)
03-30 13:08:07.528 12622 12622 D CieIDSdkLogger: onError
03-30 13:08:07.528 12622 12622 D CieIDSdkLogger: SSLProtocolException javax.net.ssl.SSLProtocolException: Read error: ssl=0x79fcd54208: Failure in SSL library, usually a protocol error
03-30 13:08:07.528 12622 12622 D CieIDSdkLogger: error:04000044:RSA routines:OPENSSL_internal:internal error (external/conscrypt/common/src/jni/main/cpp/conscrypt/native_crypto.cc:740 0x7a4cedce6b:0x00000000)

Tutte le richieste fatte alla CIE prima di queste vanno a buon fine con 90 00, oppure un trascurabile codice 6B 00 quando viene letto il certificato.
Questa non è la prima richiesta in SM alla Cie, quindi è strano che proprio questa fallisca.
L'errore si trova nella funzione respSM di Ias.kt perchè da per scontato che dalla risposta della smartcard ci siano dei dati, ma essendo l'array resp vuoto genera l'eccezione ArrayIndexOutOfBoundsException.

Inizialmente pensavo fosse il CieProvider il problema perchè con Android 10 viene usato Cipher.RSA/ECB/PKCS1Padding e non Signature.NONEwithRSA, ma poi ho visto che i dati inviati dal sito verrebbero inviati nel secondo APDU, qui fallisce il primo APDU dentro la funzione sign.
Sono disposto a fare test per risolvere il problema.

@ghost ghost mentioned this issue Mar 30, 2021
@pasqualedevita
Copy link

Grazie @etmatrix poiché utilizziamo anche noi questa libreria, puoi dirci con quale modello di dispositivo android hai rilevato il problema? grazie ancora

@ghost
Copy link
Author

ghost commented Mar 30, 2021

@pasqualedevita è un nokia 5.4

@ghost
Copy link
Author

ghost commented Mar 30, 2021

@pasqualedevita voi sapete in quale parte ricevete quell'errore?
L'errore error:04000044:RSA routines:OPENSSL_internal:internal error è generico e di solito avviene con il security provider, in questo caso il CieProvider.

@pasqualedevita
Copy link

grazie @etmatrix non siamo scesi a questo livello di dettaglio, siamo utilizzatori anche noi dell'sdk.
I log dell'issue #12 sono stati catturati dai client ma non avevamo i dispositivi a disposizione per ulteriori indagini.

@ghost
Copy link
Author

ghost commented Mar 30, 2021

Aggiungo delle informazioni che potrebbero essere utili.
Ho provato per test a spostare il sign prima che cominciasse la comunicazione via rete, naturalmente non avendo dati da segnare ho provato a mandargli un array di sette byte

sign(byteArrayOf(0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07))

la CIE risponde correttamente, sia nel primo che nel secondo APDU con 9000
Quindi possiamo escludere un problema sul sign della CIE, sembra tanto che la comunicazione SSL con okhttp interrompe la comunicazione con la CIE poi qualsiasi comando lui lo classifica come errore.

@ghost
Copy link
Author

ghost commented Mar 30, 2021

Ho trovato la causa, solo che ora ho delle difficoltà a trovare una soluzione elegante per risolvere il problema.
Il problema è il tempo. In pratica, il canale di sicurezza con la smartcard si chiude dopo un po' di tempo che non riceve comandi, questo succede proprio a ridosso della comunicazione https con il sito che richiede qualche millisecondo che è inacettabile per la smartcard aspettare.
Non so se è impostabile un tempo leggermente maggiore.
Ho risolto con una funzione che invia un comando di select file sul canale sicuro ed un controllo di lock che viene impostato dalla funzione di sign

@Throws(Exception::class)
fun readPartialFileSM(id: Int): ByteArray {
    var content = byteArrayOf()
    val selectFile = byteArrayOf(0x00, 0xa4.toByte(), 0x02, 0x04)
    val fileId = byteArrayOf(HIBYTE(id), LOBYTE(id))
    if(lock)
        return content

    sendApduSM(selectFile, fileId, null)

    return content
}

poi subito dopo aver avviato la comunicazione con NetworkClient c'è una cosa del genere:

while (true){
    Log.v("CieIDSdkLogger", "KeepAlive")
    CieIDSdk.ias!!.readPartialFileSM(0x1003)
    Thread.sleep(10)
}

Al momento è inguardabile, però sono riuscito ad autenticarmi sul sito inps.
Io spero che chi conosce la CIE sappia se c'è un modo per allargare il tempo di attesa prima che venga chiuso il canale, oppure in alternativa cercherò di migliorare la soluzione trovata.

@ghost
Copy link
Author

ghost commented Mar 31, 2021

Ho creato un fix nel mio fork. Ho fatto un bel po' di test e non ho mai avuto un problema, sempre riuscito ad autenticarmi sul sito inps, nonostante oggi risulta un po' lento.
In pratica la fix fa questo, dopo la lettura del certificato pubblico con readCertCIE, fa partire un thread con un controllo di lock, mentre riesce ad acquisire il lock ogni 10 ms manda un comando di select file sul canale sicuro, nel momento che c'è una risposta di rete e parte il sign, questo prova ad acquisire il lock, in caso di successo va avanti e svolge il suo lavoro come sempre, il thread esce silenziosamente.
Leggendo la documentazione ECC IAS 1.0.1 non sembra ci sia un timeout sul Secure Messaging, quello che mi viene da pensare che android per risparmiare energia spegne il campo NFC, così la CIE si spegne e quando viene riaccesa risponde il canale non c'è.
Forse questo è il motivo perchè alcuni device vanno ed altri no, perchè c'è chi implementa una politica aggressiva di risparmio e chi magari non è esagerato.
Agire a livello di device è abbastanza impossibile, però con questa modifica credo possiamo raggiungere un compromesso. Non è entusiasmante come soluzione, me ne rendo conto, ma a volte bisogna guardare il risultato finale.
Spero che @pasqualedevita possa provarla visto che ha molti più device a disposizione di me.

@ghost
Copy link
Author

ghost commented Mar 31, 2021

Ripensando a vecchie applicazioni mi è tornato in mente che ho avuto un problema simile con una smartcard a contatto, una volta aperto il canale sicuro con autenticazione, questo si chiudeva in automatico dopo un tempo predefinito se non venivano mandati i comandi APDU, anche se la smartcard rimaneva alimentata.
Quindi il discorso esposto nel post precedente non ha molto senso, perchè in caso di perdita di campo avremmo un'eccezione di TagLost, invece la comunicazione tra device e CIE continua senza problemi.
Se si vuole evitare il workaroud, bisogna ingegnizzare meglio l'applicazione.

  • 1 fase lettura informazioni dalla carta e salvataggio in cache, ad esempio il certificato pubblico è inutile leggerlo ogni volta, tanto non cambia e soprattutto non è segreto visto che è una chiave pubblica. La lettura è lenta visto che legge 2048 byte a pezzi di 256. Una volta messe in cache queste informazioni si leggono da li, eventualmente si prevede una scadenza.
  • 2 fase avvio connessione di rete e trasmissione dati in ssl
  • 3 fase quando bisogna fare il sign, si riapre il canale sicuro con la CIE e si fa il sign, senza aspettare nulla.

Spero che chi ha realizzato il software possa fare dei test e migliorare l'sdk ma soprattutto migliorare l'app CieID che è basato sullo stesso meccanismo.
Se ci fossero stati i sorgenti dell'app mi sarei cimentato nel migliorarla, ma in assenza ho trovato altre strade per far funzionare l'autenticazione con CIE.

@ghost ghost mentioned this issue Aug 3, 2021
rawmain added a commit to rawmain/cieid-android-sdk that referenced this issue Mar 10, 2023
Keepalive workaround per evitare chiusura anticipata del canale di sicurezza.

RiferimentI :

- italia#15 (comment)

- italia@f765088
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant