Search code examples
androidandroid-ndkopenssljava-native-interfacesingle-responsibility-principle

How to call OpenSSL SRP APIs from Android app?


I am trying to implement the SRP protocol for a Server and Client app in Android. I checked that OpenSSL supports SRP protocol but how can I access OpenSSL APIs from the Android app? Is JNI the only way to access the OpenSSL C APIs? Are there any samples that I can refer how to build the OpenSSL for Android and to call the OpenSSL SRP APIs through JNI.


Solution

  • I am trying to implement the SRP protocol

    I like SRP, too. Be sure to use Thomas Wu's specification, or version 6 of the IETF's specification.


    OpenSSL supports SRP protocol but how can I access OpenSSL APIs from the Android app? Is JNI the only way to access the OpenSSL C APIs?

    Yes.

    You might also look to Bouncy Castle for a Java implementation.


    Are there any samples that I can refer how to build the OpenSSL for Android...

    See OpenSSL and Android on the OpenSSL wiki.

    Android carries around a copy of OpenSSL, but I'm not sure of it includes SRP.


    Are there any samples that I can refer ... to call the OpenSSL SRP APIs through JNI.

    Not that I am aware. The closest you will find is the source code to s_client, options like -srpuser <user>, and data structures like srp_arg_st, and functions like ssl_srp_verify_param_cb and ssl_give_srp_client_pwd_cb.

    You can find the source code for s_client at <openssl src dir>/apps/s_client.c. Line 1365 looks interesting (from 1.0.2h):

    # ifndef OPENSSL_NO_SRP
        if (srp_arg.srplogin) {
            if (!srp_lateuser && !SSL_CTX_set_srp_username(ctx, srp_arg.srplogin)) {
                BIO_printf(bio_err, "Unable to set SRP username\n");
                goto end;
            }
            srp_arg.msg = c_msg;
            srp_arg.debug = c_debug;
            SSL_CTX_set_srp_cb_arg(ctx, &srp_arg);
            SSL_CTX_set_srp_client_pwd_callback(ctx, ssl_give_srp_client_pwd_cb);
            SSL_CTX_set_srp_strength(ctx, srp_arg.strength);
            if (c_msg || c_debug || srp_arg.amp == 0)
                SSL_CTX_set_srp_verify_param_callback(ctx,
                                                      ssl_srp_verify_param_cb);
        }
    # endif
    

    And the srp_arg_st from around line 475:

    /* This is a context that we pass to all callbacks */
    typedef struct srp_arg_st {
        char *srppassin;
        char *srplogin;
        int msg;                    /* copy from c_msg */
        int debug;                  /* copy from c_debug */
        int amp;                    /* allow more groups */
        int strength /* minimal size for N */ ;
    } SRP_ARG;
    

    Obviously, OpenSSL is native C and does not use JNI.


    How to call OpenSSL SRP APIs ...?

    At the highest levels, you need to do two or three things in C. Think of them as a supplement to a the standard TLS Client from the OpenSSL wiki. (I'm side stepping Android/JNI part).

    First, you need to set the SSL_CTX_set_srp_*_callback. The callbacks are how the library prompts your TLS client for information like username and password.

    Second, you remove all non-SRP cipher suites. That means you do not use a cipher list like "HIGH:!aNULL:!MD5:!RC4".

    Third, you use only SRP cipher suites. I'm not sure how the cipher list would look when using "HIGH:!aNULL:...". But you can hand pick the list of ciphers with:

    $ openssl ciphers -v | grep SRP | grep -v DSS | cut -f 1 -d ' '
    SRP-RSA-AES-256-CBC-SHA
    SRP-AES-256-CBC-SHA
    SRP-RSA-AES-128-CBC-SHA
    SRP-AES-128-CBC-SHA
    SRP-RSA-3DES-EDE-CBC-SHA
    SRP-3DES-EDE-CBC-SHA
    

    If you go to the openssl ciphers man page, then you should be able to cross reference SRP-RSA-AES-256-CBC-SHA with the name needed in the cipher list. Unfortunately, the SRP cipher suites are missing.

    However, you can go to ICANN's TLS paramter registry and get the names:

    • SRP-RSA-AES-256-CBC-SHA → TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA
    • SRP-AES-256-CBC-SHA → TLS_SRP_SHA_WITH_AES_256_CBC_SHA
    • SRP-RSA-AES-128-CBC-SHA → TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA
    • SRP-AES-128-CBC-SHA → TLS_SRP_SHA_WITH_AES_128_CBC_SHA
    • SRP-RSA-3DES-EDE-CBC-SHA → TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA
    • SRP-3DES-EDE-CBC-SHA → TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA

    So the string you would use for SSL_CTX_set_cipher_list or SSL_set_cipher_list:

    static const char const PREFERRED_CIPHERS[] =
       "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA:TLS_SRP_SHA_WITH_AES_256_CBC_SHA:
        TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA:TLS_SRP_SHA_WITH_AES_128_CBC_SHA:
        TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA:TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA";