Error in Sending Byte Array with Retrofit2

0

I have the following problem, I implemented a solution to send images with Retrofit2, and my web service is on a server with SSL. The certificate was recently deployed, so it was already working. Seeing some implementations, I did 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 within call is as follows:

  

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

    
asked by anonymous 27.09.2017 / 12:59

1 answer

1

According to the issue in the Retrofit documentation, it is a common mistake to use static IP to make connections with WS, only, so I understood the correct way is to use the registration address of your server, and really, after I remove the IP address the error did not appear any more the images were sent normally. It should be noted that this only occurs when connecting to secure servers with SSL certificates.

At the link above, @mnasyrov shows you how to configure your server to accept these secure connection types. It's worth a read.

    
27.09.2017 / 16:00