AWSIoT Android SDK fails to generate new certificate+key

1.8k views Asked by At

I am pretty new to Android programming, so any guidance is highly appreciated. I am trying to generate a key+certificate for connection to the AWS IoT server. It fails saying a certain URL in amazon domain has no domain-name -> address resolution. The Android log message is :

I/Adreno-EGL: <qeglDrvAPI_eglInitialize:410>: EGL 1.4 QUALCOMM build: AU_LINUX_ANDROID_LA.BF.1.1.1_RB1.05.00.02.042.013_msm8974_LA.BF.1.1.1_RB1__release_AU ()
              OpenGL ES Shader Compiler Version: E031.25.03.00
              Build Date: 01/21/15 Wed
              Local Branch: mybranch7061829
              Remote Branch: quic/LA.BF.1.1.1_rb1.7
              Local Patches: NONE
              Reconstruct Branch: AU_LINUX_ANDROID_LA.BF.1.1.1_RB1.05.00.02.042.013 +  NOTHING
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Enabling debug mode 0
D/Atlas: Validating map...
D/libc-netbsd: [getaddrinfo]: hostname=xxxxx; servname=(null); cache_mode=(null), netid=0; mark=0
D/libc-netbsd: [getaddrinfo]: ai_addrlen=0; ai_canonname=xxxxx; ai_flags=4; ai_family=0
D/libc-netbsd: [getaddrinfo]: hostname=xxxxx; servname=(null); cache_mode=(null), netid=0; mark=0
D/libc-netbsd: [getaddrinfo]: ai_addrlen=0; ai_canonname=xxxxx; ai_flags=1024; ai_family=0
D/libc-netbsd: [getaddrinfo]: hostname=xxxxx; servname=(null); cache_mode=(null), netid=0; mark=0
D/libc-netbsd: [getaddrinfo]: ai_addrlen=0; ai_canonname=xxxxx; ai_flags=4; ai_family=0
I/art: Thread[1,tid=14654,WaitingForJniOnLoad,Thread*=0xb4827800,peer=0x75c35b48,"main"] recursive attempt to load library "/system/lib/libhook_jni.so"
E/MediaProfilesEx-JNI: register_com_lge_media_MediaProfilesEx
E/MediaRecorderEx-JNI: register_com_lge_media_MediaRecorderEx
D/AudioSystemEx: register_com_lge_media_LGAudioSystem
E/SurfaceControlEx: register_com_lge_view_SurfaceControlEx
I/art: Thread[1,tid=14654,WaitingForJniOnLoad,Thread*=0xb4827800,peer=0x75c35b48,"main"] recursive attempt to load library "/system/lib/libhook_jni.so"
D/LGMtpDatabaseJNI: register_android_mtp_LGMtpDatabase
I/art: Thread[1,tid=14654,WaitingForJniOnLoad,Thread*=0xb4827800,peer=0x75c35b48,"main"] recursive attempt to load library "/system/lib/libhook_jni.so"
D/LGMtpServerJNI: register_android_mtp_LGMtpServer
I/art: Thread[1,tid=14654,WaitingForJniOnLoad,Thread*=0xb4827800,peer=0x75c35b48,"main"] recursive attempt to load library "/system/lib/libhook_jni.so"
E/MediaPlayerEx-jni: register_com_lge_view_MediaPlayerEx
I/art: Thread[1,tid=14654,WaitingForJniOnLoad,Thread*=0xb4827800,peer=0x75c35b48,"main"] recursive attempt to load library "/system/lib/libhook_jni.so"

       [ 12-29 22:00:44.433 14654:14654 D/         ]
       register_com_lge_emoji_EmojiUtil
D/libc-netbsd: [getaddrinfo]: hostname=xxxxx; servname=(null); cache_mode=(null), netid=0; mark=0
D/libc-netbsd: [getaddrinfo]: ai_addrlen=0; ai_canonname=xxxxx; ai_flags=4; ai_family=0
D/libc-netbsd: [getaddrinfo]: hostname=xxxxx; servname=(null); cache_mode=(null), netid=0; mark=0
D/libc-netbsd: [getaddrinfo]: ai_addrlen=0; ai_canonname=xxxxx; ai_flags=4; ai_family=0
W/System.err: com.amazonaws.AmazonClientException: Unable to execute HTTP request: Unable to resolve host "execute-api.eu-central-1.amazonaws.com": No address associated with hostname
W/System.err:     at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:424)
W/System.err:     at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:199)
W/System.err:     at com.amazonaws.services.iot.AWSIotClient.invoke(AWSIotClient.java:3713)
W/System.err:     at com.amazonaws.services.iot.AWSIotClient.createKeysAndCertificate(AWSIotClient.java:754)
W/System.err:     at com.home.tukai.awsiottryout01.MainActivity$3.run(MainActivity.java:188)
W/System.err:     at java.lang.Thread.run(Thread.java:818)
W/System.err: Caused by: java.net.UnknownHostException: Unable to resolve host "execute-api.eu-central-1.amazonaws.com": No address associated with hostname
W/System.err:     at java.net.InetAddress.lookupHostByName(InetAddress.java:435)
W/System.err:     at java.net.InetAddress.getAllByNameImpl(InetAddress.java:255)
W/System.err:     at java.net.InetAddress.getAllByName(InetAddress.java:218)
W/System.err:     at com.android.okhttp.HostResolver$1.getAllByName(HostResolver.java:29)
W/System.err:     at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:232)
W/System.err:     at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:124)
W/System.err:     at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:303)
W/System.err:     at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:242)
W/System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:397)
W/System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:118)
W/System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:229)
W/System.err:     at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
W/System.err:     at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:25)
W/System.err:     at com.amazonaws.http.UrlHttpClient.writeContentToConnection(UrlHttpClient.java:156)
W/System.err:     at com.amazonaws.http.UrlHttpClient.execute(UrlHttpClient.java:70)
W/System.err:     at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:356)
W/System.err:   ... 5 more
E/AWS: Exception occurred when generating new private key and certificate.
W/IInputConnectionWrapper: showStatusIcon on inactive InputConnection

Now, interestingly, if I load a KeyStore into the phone into the location of the app's package, then it works fine. The (KeyStore==null) is not checked then. The Keystore here is created out of downloaded certificates from my AWS account associated to this THING. My question is: Am I doing anything wrong here ? If not, then what is it that I am missing out ?

I am trying to following this link to create my program : https://github.com/awslabs/aws-sdk-android-samples/blob/master/AndroidPubSub/src/com/amazonaws/demo/androidpubsub/PubSubActivity.java

The relevant section of my program :

private static final String CUSTOMER_SPECIFIC_ENDPOINT = "a228q6docijn1f.iot.eu-central-1.amazonaws.com";
// Cognito pool ID. For this app, pool needs to be unauthenticated pool with
// AWS IoT permissions.
private static final String COGNITO_POOL_ID = "eu-central-1:36b201e2-d55e-4601-9430-031fc7990291";
// Name of the AWS IoT policy to attach to a newly created certificate
private static final String AWS_IOT_POLICY_NAME = "all-iot";

// Region of AWS IoT
private static final Regions MY_REGION = Regions.EU_CENTRAL_1;
// Filename of KeyStore file on the filesystem
private static final String KEYSTORE_NAME = "KeyStoreAlfred01.bks";
// Password for the private key in the KeyStore
private static final String KEYSTORE_PASSWORD = "<THIS I FILLED IN CORRECTLY>";
// Certificate and key aliases in the KeyStore
private static final String CERTIFICATE_ID = "keystorealfred01";


AWSIotClient mIotAndroidClient;
AWSIotMqttManager mqttManager;
String clientId;
String keystorePath;
String keystoreName;
String keystorePassword;

KeyStore clientKeyStore = null;
String certificateId;

CognitoCachingCredentialsProvider credentialsProvider;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    btnGenNumber = (Button) findViewById(R.id.btnGenNumber);
    btnConnect = (Button) findViewById(R.id.btnConnect);
    btnYoutubeSearch = (Button) findViewById(R.id.btnYoutubeSearch);

    btnGenNumber.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Random r = new Random();
            int num = r.nextInt(51);

            try {
                mqttManager.publishString(Integer.toString(num), "test", AWSIotMqttQos.QOS0);
                Toast.makeText(getApplicationContext(), "Published number " + Integer.toString(num), Toast.LENGTH_LONG).show();

                Log.i(LOG_TAG, "Publish done");
            } catch (Exception e) {
                Log.e(LOG_TAG, "Publish error.", e);
            }

            Log.i(LOG_TAG, "Button generated a new number" + num);
        }
    });

    btnYoutubeSearch.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent(Intent.ACTION_SEARCH);
            intent.setPackage("com.google.android.youtube");
            intent.putExtra("query", "Android");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }
    });
    // Initialize the AWS Cognito credentials provider
    credentialsProvider = new CognitoCachingCredentialsProvider(
            getApplicationContext(), // context
            COGNITO_POOL_ID, // Identity Pool ID
            MY_REGION // Region
    );
    Log.i(LOG_TAG, "Credentials provider output " + credentialsProvider.toString());
    Region region = Region.getRegion(MY_REGION);
    mIotAndroidClient = new AWSIotClient(credentialsProvider);
    mIotAndroidClient.setRegion(region);

    //keystorePath = "/mnt/sdcard/awsIOTtryout01";
    keystorePath = getFilesDir().getPath();
    keystoreName = KEYSTORE_NAME;
    keystorePassword = KEYSTORE_PASSWORD;
    certificateId = CERTIFICATE_ID;

    Log.i(LOG_TAG, "Begin certificate load");

    // To load cert/key from keystore on filesystem
    try {
        if (AWSIotKeystoreHelper.isKeystorePresent(keystorePath, keystoreName)) {
            if (AWSIotKeystoreHelper.keystoreContainsAlias(certificateId, keystorePath,
                    keystoreName, keystorePassword)) {
                Log.i(LOG_TAG, "Certificate " + certificateId
                        + " found in keystore - using for MQTT.");
                // load keystore from file into memory to pass on connection
                clientKeyStore = AWSIotKeystoreHelper.getIotKeystore(certificateId,
                        keystorePath, keystoreName, keystorePassword);
                Log.i(LOG_TAG, "Certificate loading complete");
                //btnConnect.setEnabled(true);
            } else {
                Log.i(LOG_TAG, "Key/cert " + certificateId + " not found in keystore.");
            }
        } else {
            Log.i(LOG_TAG, "Keystore " + keystorePath + "/" + keystoreName + " not found.");
        }
    } catch (Exception e) {
        Log.e(LOG_TAG, "An error occurred retrieving cert/key from keystore.", e);
    }

    if (clientKeyStore == null) {
        Toast.makeText(getApplicationContext(),"Cert/key was not found in keystore - creating new key and certificate.",Toast.LENGTH_SHORT).show();
        Log.i(LOG_TAG, "Cert/key was not found in keystore - creating new key and certificate.");
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // Create a new private key and certificate. This call
                    // creates both on the server and returns them to the
                    // device.
                    CreateKeysAndCertificateRequest createKeysAndCertificateRequest =
                            new CreateKeysAndCertificateRequest();
                    createKeysAndCertificateRequest.setSetAsActive(true);
                    Log.i(LOG_TAG,"keys + cert generation : "+createKeysAndCertificateRequest.toString());
                    final CreateKeysAndCertificateResult createKeysAndCertificateResult;
                    createKeysAndCertificateResult =mIotAndroidClient.createKeysAndCertificate(createKeysAndCertificateRequest);

                    //Log.i(LOG_TAG,"Cert ID: New certificate generation done.");
                    //Toast.makeText(getApplicationContext(),"New certificate created", Toast.LENGTH_SHORT).show();
                    // store in keystore for use in MQTT client
                    // saved as alias "default" so a new certificate isn't
                    // generated each run of this application
                    AWSIotKeystoreHelper.saveCertificateAndPrivateKey(certificateId,
                            createKeysAndCertificateResult.getCertificatePem(),
                            createKeysAndCertificateResult.getKeyPair().getPrivateKey(),
                            keystorePath, keystoreName, keystorePassword);

                    // load keystore from file into memory to pass on connection

                    clientKeyStore = AWSIotKeystoreHelper.getIotKeystore(certificateId,
                            keystorePath, keystoreName, keystorePassword);
                    // Attach a policy to the newly created certificate
                    // This flow assumes the policy was already created in
                    // AWS IoT and we are now just attaching it to the
                    // certificate.

                    AttachPrincipalPolicyRequest policyAttachRequest =
                            new AttachPrincipalPolicyRequest();
                    policyAttachRequest.setPolicyName(AWS_IOT_POLICY_NAME);
                    policyAttachRequest.setPrincipal(createKeysAndCertificateResult.getCertificateArn());
                    mIotAndroidClient.attachPrincipalPolicy(policyAttachRequest);
                } catch (Exception e) {
                   // Toast.makeText(getApplicationContext(),"Exception occured when generating new key+cert",Toast.LENGTH_SHORT).show();
                    e.printStackTrace();
                    Log.e(LOG_TAG,"Exception occurred when generating new private key and certificate.",e);
                }
            }
        }).start();
    }

I am using ANdroid Studio 2.2.2 using Min API : 9 for the project. ANy help is highly appreciated !

Update : When the KeyStore file ( with certs ) is present inside the phone's mem location of this package, then the Android logs look like :

/CognitoCachingCredentia`enter code here`lsProvider: Loading credentials from SharedPreferences
I/AWS: Credentials provider output com.amazonaws.auth.CognitoCachingCredentialsProvider@2d7ae714
I/AmazonWebServiceClient: {execute-api, eu-central-1} was not found in region metadata, trying to construct an endpoint using the standard pattern for this region: 'execute-api.eu-central-1.amazonaws.com'.
I/AWS: Begin certificate load
I/AWS: Certificate keystorealfred01 found in keystore - using for MQTT.
I/AWS: Certificate loading complete
D/OpenGLRenderer: Render dirty regions requested: true
I/Adreno-EGL: <qeglDrvAPI_eglInitialize:410>: EGL 1.4 QUALCOMM build: AU_LINUX_ANDROID_LA.BF.1.1.1_RB1.05.00.02.042.013_msm8974_LA.BF.1.1.1_RB1__release_AU ()
              OpenGL ES Shader Compiler Version: E031.25.03.00
              Build Date: 01/21/15 Wed
              Local Branch: mybranch7061829
              Remote Branch: quic/LA.BF.1.1.1_rb1.7
              Local Patches: NONE
              Reconstruct Branch: AU_LINUX_ANDROID_LA.BF.1.1.1_RB1.05.00.02.042.013 +  NOTHING
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Enabling debug mode 0
D/Atlas: Validating map...
W/IInputConnectionWrapper: showStatusIcon on inactive InputConnection
I/Timeline: Timeline: Activity_idle id: android.os.BinderProxy@25603903 time:661926148
2

There are 2 answers

0
M.Praveen Kumar On

Please try to add the below line :

mIotAndroidClient.setEndpoint("iot.ap-northeast-1.amazonaws.com");

After this line : mIotAndroidClient.setRegion(region);

0
Ashutosh Thakur On

I can see following line in your exception logs:

Unable to resolve host "execute-api.eu-central-1.amazonaws.com"

This tells me that you are not hitting the right endpoint for IoT.

For calling CreateKeyAndCertificates in eu-central-1 you need to hit iot.eu-central-1.amazonaws.com

You can try setting this endpoint using:

mIotAndroidClient.setEndpoint("iot.eu-central-1.amazonaws.com");

Thanks Ashutosh