Error sending byte array with Retrofit2

Asked

Viewed 79 times

0

I have the following problem, implemented a solution for sending images with Retrofit2, and my web service is on a server with SSL. The certificate was recently implemented, so it was already working. Seeing some implementations, I made the following implementation:

private void sendImage() {
    OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
    OkHttpClient okHttpClient = builder.build();

    Gson gson = new GsonBuilder().setLenient().registerTypeAdapter(Usuario.class, new ImageDes()).create();

    Retrofit retrofit = new Retrofit
            .Builder()
            .baseUrl(context.getResources().getString(R.string.sync_adapter_conn))
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();

    byte[] imageBinary = BinaryBytes.getResourceInBytes(image);
    RequestBody requestBody = RequestBody.create(MediaType.parse("image/png"), imageBinary);
    ImageApi imageApi = retrofit.create(ImageApi.class);

    Call<Request> call = imageApi.sendImgRequest(nameImage, requestBody);

    builder.hostnameVerifier(new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {

            Certificate[] certs;
            try {
                certs = session.getPeerCertificates();
            } catch (SSLException e) {
                return false;
            }
            X509Certificate x509 = (X509Certificate) certs[0];
            // We can be case-insensitive when comparing the host we used to
            // establish the socket to the hostname in the certificate.
            String hostName = hostname.trim().toLowerCase(Locale.ENGLISH);
            // Verify the first CN provided. Other CNs are ignored. Firefox, wget,
            // curl, and Sun Java work this way.
            String firstCn = getFirstCn(x509);
            if (matches(hostName, firstCn)) {
                return true;
            }
            for (String cn : getDNSSubjectAlts(x509)) {
                if (matches(hostName, cn)) {
                    return true;
                }
            }
            return false;

        }
    });

    call.enqueue(new Callback<Request>() {
        @Override
        public void onResponse(Call<Request> call, Response<Request> response) {
            Log.i("IMAGE_CALL", response.message());
        }

        @Override
        public void onFailure(Call<Request> call, Throwable t) {
            Log.e("ERRO_CALL", t.getMessage());
        }
    });
}

private String getFirstCn(X509Certificate cert) {
    /*
     * Sebastian Hauer's original StrictSSLProtocolSocketFactory used
     * getName() and had the following comment:
     *
     *      Parses a X.500 distinguished name for the value of the
     *     "Common Name" field.  This is done a bit sloppy right
     *     now and should probably be done a bit more according to
     *     <code>RFC 2253</code>.
     *
     * I've noticed that toString() seems to do a better job than
     * getName() on these X500Principal objects, so I'm hoping that
     * addresses Sebastian's concern.
     *
     * For example, getName() gives me this:
     * 1.2.840.113549.1.9.1=#16166a756c6975736461766965734063756362632e636f6d
     *
     * whereas toString() gives me this:
     * [email protected]
     *
     * Looks like toString() even works with non-ascii domain names!
     * I tested it with "&#x82b1;&#x5b50;.co.jp" and it worked fine.
     */
    String subjectPrincipal = cert.getSubjectX500Principal().toString();
    StringTokenizer st = new StringTokenizer(subjectPrincipal, ",");
    while (st.hasMoreTokens()) {
        String tok = st.nextToken();
        int x = tok.indexOf("CN=");
        if (x >= 0) {
            return tok.substring(x + 3);
        }
    }
    return null;
}

The error returned by the log, inside the call is the following:

E/ERRO_CALL: Hostname [IP Server] not verified: Certification: [certificate]
DN: CN=[url]
subjectAltNames: [url, url]

1 answer

1


According to the Issue which is in the Retrofit documentation, it is a common mistake to use static IP to make connections with WS, only, from what I understood the correct one is to use the registration address of your server, and actually, after I remove the IP address the error no longer appeared to the images were sent normally. It is worth noting that this only happens when you have connection to secure servers, with SSL certificates.

On the link above, @mnasyrov shows you how to set up your server to accept these types of secure connection. It’s worth a read.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.