I'm trying to make my app communicate with my server via https.
As I don't want to pay to get my server certificate signed by a trusted CA, the solution is to use a self signed certificate.
So, I've created my caconfig.cnf as follows:
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
dir = ./demoCA # top dir
database = $dir/index.txt # index file.
new_certs_dir = $dir/newcerts # new certs dir
certificate = $dir/cacert.pem # The CA cert
serial = $dir/serial # serial no file
private_key = $dir/private/cakey.pem # CA private key
RANDFILE = $dir/private/.rand # random number file
default_days = 365 # how long to certify for
default_crl_days = 30 # how long before next CRL
default_md = md5 # md to use
policy = policy_any # default policy
email_in_dn = no # Don't add the email into cert DN
name_opt = ca_default # Subject name display option
cert_opt = ca_default # Certificate display option
copy_extensions = none # Don't copy extensions from request
[ policy_any ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
Then, I've created and signed my certificate using the following commands:
$ mkdir myCA myCA/private myCA/newcerts
$ echo "01" > myCA/serial
$ touch demoCA/index.txt
$ openssl genrsa -des3 -out myCA/private/cakey.pem 1024
$ openssl req -new -x509 -days 3650 -key myCA/private/cakey.pem -out myCA/cacert.pem
$ openssl req -sha1 -newkey rsa:2048 -keyout server-key.pem -out server-cert-req.pem -subj '/CN=myhost/' -nodes
$ openssl ca -config caconfig.cnf -in server-cert-req.pem -out server-cert.pem
$ openssl x509 -inform PEM -in cacert.pem -outform DER -out certificate.cer
$ rm server-cert-req.pem
In my nodejs server code, I'm creating the https server like this:
var express = require('express');
var https = require('https');
var PORT = 443;
var app = express();
app.get('/', function (req, res) {
res.send("Server is working");
});
var httpsOptions = {
key: fs.readFileSync('server-key.pem'),
cert: fs.readFileSync('server-cert.pem')
};
https.createServer(httpsOptions, app).listen(PORT, function() {
console.log('%s: Node server started on port %d ...', Date(Date.now() ), PORT);
});
In order to test if everything is correct, I've also created a node client script, which makes a request to my server. Here is the code for my node client:
var https = require('https');
var fs = require('fs');
var request = https.request({
host: 'myhost',
port: 443,
path: '/',
method: 'GET',
rejectUnauthorized: true,
// Once it is self signed, I'm using my server certificate (public key).
ca: [fs.readFileSync('cacert.pem').toString()]
}, function(response) {
response.on('data', function(data) {
console.log(data.toString());
});
});
request.on('error', function(err) {
console.log(err);
})
request.end();
When I run my node client script, it works perfectly. On the other hand, the Android Volley Examples app, which I'm using to check how Volley works with https, is not working. Below, I'm describing all the steps I've followed in order to try to make it work.
I've created a .bks file using my certificate.cer file using the following command:
keytool -importcert -v -trustcacerts -file "certificate.cer" -alias IntermediateCA -keystore "res/raw/my_keystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-146.jar" -storetype BKS -storepass mysecret
Then, I've verified if the certificate was imported correctly into the .bks as follows:
keytool -list -keystore "res/raw/my_keystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-146.jar" -storetype BKS -storepass mysecret
And I got the following output, that means it's correct:
Keystore type: BKS
Keystore provider: BC
Your keystore contains 1 entry
imeto_alias, Oct 16, 2014, trustedCertEntry,
Certificate fingerprint (SHA1): 03:DC:A1:6A:9B:1D:AD:59:A9:9B:1F:C2:43:7E:80:07:3B:B6:BE:CB
I've came across to this tutorial, and, as I'm using Volley, I've decided to follow it. So, below are the following changes I've made to the example project.
Got Volley from git clone https://android.googlesource.com/platform/frameworks/volley
Got Android Volley Examples project from git clone git://github.com/ogrebgr/android_volley_examples.git
Copied my_keystore.bks containing the self-signed public key in res/raw;
Opened Act_SsSslHttpClient in the examples project, found "R.raw.test" and replaced it with R.raw.my_keystore;
Found "new SslHttpClient(" and replaced the default password "test123″ with "mysecret";
Replaced "44400" with the HTTPS port of my server/virtualhost ("443"). (I could also remove this parameter since "443" is the default port;
Replaced "https://tp.bolyartech.com:44400/https_test.html" with my server URL.
Started the app, went to "HTTPS with self-signed cert", then "Execute HTTPS request"
But, when I pressed the button, I got the following exception:
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
Below, is my JavaCode...
public class Act_SsSslHttpClient extends Activity {
private TextView mTvResult;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act__ss_ssl_http_client);
mTvResult = (TextView) findViewById(R.id.tv_result);
Button btnSimpleRequest = (Button) findViewById(R.id.btn_simple_request);
btnSimpleRequest.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Replace R.raw.test with your keystore
InputStream keyStore = getResources().openRawResource(R.raw.my_keystore);
// Usually getting the request queue shall be in singleton like in {#seeAct_SimpleRequest}
// Current approach is used just for brevity
RequestQueue queue = Volley.newRequestQueue(Act_SsSslHttpClient.this,
new ExtHttpClientStack(new SslHttpClient(keyStore,
"mysecret")));
StringRequest myReq = new StringRequest(Method.GET,
"https://myServerURL/",
createMyReqSuccessListener(),
createMyReqErrorListener());
queue.add(myReq);
}
});
}
...
}
Does anybody know the solution?
Thank you.
I am using self signed certificate in my test environment. To make it work I call this method in my Application class in onCreate method. It makes all certificates accepted. It is not save, but for test purposes is ok.
#Override
public void onCreate() {
nuke();
super.onCreate();
}
public static void nuke() {
try {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}
#Override
public void checkClientTrusted(X509Certificate[] certs,
String authType) {}
#Override
public void checkServerTrusted(X509Certificate[] certs,
String authType) {}
} };
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection
.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection
.setDefaultHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {}
}
Related
I'm setting up a pipeline for an android device to request a certificate like so:
var subjectName = $"CN={GetFQDN()},O=My Org,OU=Test,T=Test,ST=OK,C=US";
// Create new Object for Issuer and Subject
var subject = new X509Name(subjectName);
// Generate the key Value Pair, which in our case is a public Key
var random = new SecureRandom();
const int strength = 2048;
var keyGenerationParameters = new KeyGenerationParameters(random, strength);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
AsymmetricCipherKeyPair subjectKeyPair = keyPairGenerator.GenerateKeyPair();
//PKCS #10 Certificate Signing Request
Pkcs10CertificationRequest csr = new Pkcs10CertificationRequest("SHA1WITHRSA", subject, subjectKeyPair.Public, null, subjectKeyPair.Private);
//Convert BouncyCastle CSR to .PEM file.
StringBuilder CSRPem = new StringBuilder();
PemWriter CSRPemWriter = new PemWriter(new StringWriter(CSRPem));
CSRPemWriter.WriteObject(csr);
CSRPemWriter.Writer.Flush();
//get CSR text
var CSRtext = CSRPem.ToString();
// Write content into a Txt file
using (StreamWriter f = new StreamWriter(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), #"MyCsr.txt"), false))
{
f.Write(CSRtext);
}
CSRPem = new StringBuilder();
CSRPemWriter = new PemWriter(new StringWriter(CSRPem));
CSRPemWriter.WriteObject(subjectKeyPair.Private);
CSRPemWriter.Writer.Flush();
CSRtext = CSRPem.ToString();
using (StreamWriter f = new StreamWriter(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData), #"PrivateKey.pem"), false))
{
f.Write(CSRtext);
}
The csr is sent to a Windows CA server, then the resulting .cer is combined with the private key using the following openssl command (on Windows 11):
openssl pkcs12 -export -in myCer.cer -inkey myKey.pem -out myPfx.pfx
Regardless of what the password is set to, including blank, the certificate will install correctly on any Windows PC but says incorrect password on any Android device, when installing through the system dialogue. When trying to decode the .pfx programmatically, like:
Application.Context.Assets.Open("newCert.pfx").CopyTo(mmstream);
byte[] b = mmstream.ToArray();
var myCert = new X509Certificate2(b, String.Empty);
I get the following error:
System.Security.Cryptography.CryptographicException: Unable to decode certificate. ---> System.Security.Cryptography.CryptographicException: `MonoBtlsPkcs12.Import` failed.
It seems like Android may be using a different algorithm to encrypt using the password by default? But every post I've found about exporting to Android from openssl just uses the default arguments.
Looks like Android accepts certs I generate with 32 bit openssl and not 64 bit. Unsure why this is.
openssl pkcs12 -export -in myCer.cer -inkey myKey.pem -out myPfx.pfx
worked fine in 32 bit openssl
This is the first time I am doing this SSL pinning on Android.
When creating OkHttp, I am adding this code:
certificatePinner(
CertificatePinner.Builder().add(
"url of the server",
"sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
).build()
)
the second parameter expects this:
SHA-256 or SHA-1 hashes. Each pin is a hash of a certificate's Subject Public Key Info, base64-encoded and prefixed with either sha256/ or sha1/.
I was given a certificate in a txt file that starts with --BEGIN CERTIFICATE-- and ends with --END CERTIFICATE--.
I am struggling to extract the hash of Public Key Info and convert it to base64.
So far I have tried these methods:
Method 1:
I put the certificate contents without BEGIN CERTIFICATE and END CERTIFICATE into some string variable. Tried to convert it into X509Certificate.
private fun certificateFromString(base64: String): X509Certificate? {
val decoded = Base64.decode(base64, Base64.NO_WRAP)
val inputStream = ByteArrayInputStream(decoded)
return CertificateFactory.getInstance("X.509").generateCertificate(inputStream) as? X509Certificate
}
Then I pass this certificate here to get Sha256 hash of the public key. Also, pay attention to c.encoded and c.publicKey.encoded. I am not sure if the method works correctly.
private fun getFingerprint(c: X509Certificate?): String {
var certificate = ""
try {
val md = MessageDigest.getInstance("SHA-256")
var publicKey = ByteArray(0)
if (c != null) {
publicKey = md.digest(c.encoded) // I tried both
publicKey = md.digest(c.publicKey.encoded) // I tried both
}
val hexString = StringBuilder()
for (aPublicKeyByte in publicKey) {
val appendString = Integer.toHexString(0xFF and aPublicKeyByte.toInt())
if (appendString.length == 1) hexString.append("0")
hexString.append(appendString)
}
certificate = hexString.toString()
} catch (e1: NoSuchAlgorithmException) {
e1.printStackTrace()
} catch (e1: CertificateEncodingException) {
e1.printStackTrace()
}
return certificate
}
then I am converting that string result to base64 like this:
private fun base64(openKey: String): String {
return Base64.encodeToString(openKey.toByteArray(), Base64.NO_WRAP).toString()
}
then I add the resulting String into the CertificatePinner class as sha256/resultingStringInBase64.
Method 2:
I changed the .txt into .pem in order to use openssl command line tools.
openssl rsa -in myCert.pem -pubout> myCert.pub
it returned writing RSA key
and when I open the generated myCert.pub, I see a text with ---BEGUN PUBLIC KEY--- and ---END PUBLIC KEY--- and a long list of letters between them.
Then I ran this to extract the sha256 hash:
openssl rsa -in myCert.pub -pubin -outform der | openssl dgst -sha256
this gave me a 64 character string 2c180286549...b1ba7.
Then I ran the command again but added base64 conversion.
openssl rsa -in myCert.pub -pubin -outform der | openssl dgst -sha256 | openssl enc -base64
The result is completely different than Method 1. Should it be the same? If so, could someone point me in the right direction? Or show how to properly get the SHA256 of Public Key.
My method I just used recently and worked succesfully:
In your Terminal, where the folder containing public key file is located, write the command:
openssl x509 -in yourFile.pem -pubkey -noout | open ssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
The result will be the your desired string (encoded in base64, which means that it'll have 44 characters, including an equal (=) symbol at the end), and must be placed in your Android code after sha256/....
Also, several methods could generate different hashes, so you can have multiple valid strings, meaning that both your generated hashes could be correct.
First of all, sorry i'm not good English. and it's my first question.
I'm trying to connect android and Mosquitto-broker in windows
with self-signed-certificate.
I succeeded connect mosquitto-broker and mosquitto_pub with my self-signed-certificate( ca.crt, server.key, server.crt, client.key, client.crt )
broker config file :
port 8883
cafile : ~~~/ca.crt.pem
keyfile : ~~~/server.key.pem
certfile : ~~~/server.crt.pem
tls_version tlsv1.2
require_certificate true
publish command :
mosquitto_pub -h ~~ -p ~~ -t ~~ -m ~~ --cafile ~~/ca.crt.pem --key
~~/client.key.pem --cert ~~/client.crt.pem
--> it works well
mosquitto_pub -h ~~ -p ~~ -t ~~ -m ~~ --cafile ~~/ca.crt.pem
--> it not works. i don't know why it doesn't work.
but, the important thing is i can't connect to android.
I've searched, android use .bks file to tls/ssl. so i tried to make .bks file with my files on above.
The order in which I created the file is .p12 -> .jks -> .bks
and these command :
.p12 : > openssl pkcs12 -export -in client.crt.pem -inkey client.key.pem -out client.p12 -certfile ca.crt.pem
.jks : > keytool -importkeystore -srckeystore client.p12 -srcstoretype pkcs12 -srcstorepass 123123 -destkeystore client.jks -deststoretype jks -deststorepass 123123
.bks : > keytool -importkeystore -srckeystore client.jks -srcstoretype JKS -srcstorepass 123123 -destkeystore client.bks -deststoretype BKS-v1 -deststorepass 123123 -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk15on-162.jar
my android code is
....
mqttAndroidClient = new MqttAndroidClient(this, "ssl://" + ipAdd.getText().toString() + ":" + port.getText().toString(), ClientID);
try {
/**/
MqttConnectOptions options = new MqttConnectOptions();
InputStream input = this.getApplication().getAssets().open("server.bks");
options.setSocketFactory(new TLSSocketFactory(input, "123123"));
IMqttToken token = mqttAndroidClient.connect(options);
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
....
public class TLSSocketFactory extends SSLSocketFactory {
private SSLSocketFactory internalSSLSocketFactory;
public TLSSocketFactory(InputStream keyStore, String password) throws KeyManagementException, NoSuchAlgorithmException, IOException, CertificateException, KeyStoreException {
KeyStore ts;
ts = KeyStore.getInstance("BKS");
ts.load(keyStore, password.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(ts);
TrustManager[] tm = tmf.getTrustManagers();
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(null, tm, null);
internalSSLSocketFactory = context.getSocketFactory();
}
....
Occured message on broker is
1564452813: OpenSSL Error: error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown
I don't know what it mean
please help me the masters.
I found it!
the cause were not code and keys.
in my bundle dependencies part :
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.1'
were the cause.
error is not occued below the mqttv3:1.2.1 version.
i don't know the difference both version.
I am integrating the JITR by follwing this article.
https://aws.amazon.com/blogs/iot/just-in-time-registration-of-device-certificates-on-aws-iot/
I am done with all these steps and able to authenticate the certificate through command-line 'mosquitto_pub'.
First time when I run 'mosquitto_pub' command it calls lambda function to authorize it and attach policy and second time it publish message to IOT successfully.
Here is command that I am using.
mosquitto_pub --cafile ../root.cert --cert hassanAndCACert.crt --key hassan.key -h <###>.iot.us-east-1.amazonaws.com
-p 8883 -q 1 -t topic5 -i 123456789 --tls-version tlsv1.2 -m '{"hello":"3"}' -d
But when I try to authenticate this in android SDK I am getting 'handshake' fail error. Here is exception that I am getting.
MqttException (0) - javax.net.ssl.SSLHandshakeException: Handshake
failedat
org.eclipse.paho.client.mqttv3.internal.ExceptionHelper.createMqttException(ExceptionHelper.java:38)at
org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:664)at
java.lang.Thread.run(Thread.java:818)Caused by:
javax.net.ssl.SSLHandshakeException: Handshake failedat
com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:441)at
org.eclipse.paho.client.mqttv3.internal.SSLNetworkModule.start(SSLNetworkModule.java:93)at
org.eclipse.paho.client.mqttv3.internal.ClientComms$ConnectBG.run(ClientComms.java:650)
... 1 moreCaused by: javax.net.ssl.SSLProtocolException: SSL handshake
terminated: ssl=0xb91e9b40: Failure in SSL library, usually a protocol
errorerror:100c5416:SSL
routines:ssl3_read_bytes:SSLV3_ALERT_CERTIFICATE_UNKNOWN
(external/boringssl/src/ssl/s3_pkt.c:972 0xb9215530:0x00000001)at
com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native
Method)at
com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:353)
Interestingly if device-certificate is already active and we try to publish message through android it get published successfully. The only problem is to authenticate the certificate at first call. If my code is faulty it should not send message against activated-certificates.
The difference that I see between mosquitto call and the android-code is that mosquitto is making a single command to connect and publish the message, where as PAHO-MQTT in AWS SDK needs to connect first before publishing, and I get exception in 'connect'. I even did not get any logs in AWS logs.
Possible Reasons
SSL/TLS Handshake can fail for various reasons and not only for certificate validation problems.
It could be for:
Not sharing same cipher suites
Not sharing SSL versions
Certificate validation
Intent to change TLS version
Others issues
The best way to figure out what your problem is is to install Wireshark and see the handshake messages. Then based on the SSL alert message sent from server to client you can have more information on the SSL handshake failure, where specifically it happened.
Possible solution
Solution No. 1: This link might also help: Received fatal alert: handshake_failure through SSLHandshakeException
Solution No. 2: Could you try to upgrade the keystore for your Android App?
Helpful resources
https://serverfault.com/questions/639837/openssl-s-client-shows-alert-certificate-unknown-but-all-server-certificates-app#639866
https://aws.amazon.com/de/blogs/iot/just-in-time-registration-of-device-certificates-on-aws-iot/
https://aws.amazon.com/de/blogs/mobile/use-your-own-certificate-with-aws-iot/
https://stackoverflow.com/a/6353956/5157221
Make your own KeyStoreHelper that put CA Cert into your KeyStore, and use it instead of AWS IoT SDK's KeyStoreHelper.
Note: I omitted all exception handlings in the codes below, and createKeyPair(), createCSR(), parsePemObject() and signCSR() are my methods.
public class MyKeystoreHelper {
public KeyStore createKeystoreJIT(String certId, String keystorePath,
String keystoreName, String keystorePassword, HashMap<String, String> directory) {
// Generate KeyPair
KeyPair key = createKeyPair();
// Generate CSR
PKCS10CertificationRequest csr = createCSR(key, directory);
// Read CA Private key
PEMKeyPair pemKey = (PEMKeyPair)parsePemObject(context, PATH_TO_CAROOT_KEY_FILE);
KeyPair caKey = new JcaPEMKeyConverter().getKeyPair(pemKey);
// Read CA Cert
X509CertificateHolder pemCert = (X509CertificateHolder)parsePemObject(context, PATH_TO_CAROOT_CERT_FILE);
X509Certificate caCert = new JcaX509CertificateConverter().getCertificate(pemCert);
X500Name issuer = pemCert.getIssuer();
// Generate CA Signed CSR
X509Certificate cert = signCSR(csr, caKey.getPrivate(), caCert, issuer);
// Create Key Store
saveKeystore(certId, cert, caCert, key.getPrivate(), keystorePath, keystoreName, keystorePassword); // <-- HERE!! Pass CA Cert
KeyStore keystore = getKeystore(certId, keystorePath, keystoreName, keystorePassword);
return keystore;
}
....
private boolean saveKeystore(String certId, X509Certificate cert, X509Certificate caCert,
PrivateKey privatekey, String keystorePath, String keystoreName, String keystorePassword) {
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
File keystoreFile = new File(keystorePath, keystoreName);
if( ! keystoreFile.exists()) {
createKeystore(keystorePath, keystoreName, keystorePassword);
}
FileInputStream fis = new FileInputStream(keystoreFile);
keystore.load(fis, keystorePassword.toCharArray());
fis.close();
keystore.setCertificateEntry(certId, cert);
keystore.setKeyEntry(certId, privatekey, keystorePassword.toCharArray(), new Certificate[] { cert, caCert }); // <-- HERE!! put CA Cert
String caCertId = certId + "_CA";
keystore.setCertificateEntry(caCertId, caCert);
keystore.setKeyEntry(caCertId, privatekey, keystorePassword.toCharArray(), new Certificate[] { caCert });
String keystoreFileAndPath;
if(keystorePath.endsWith("/")) {
keystoreFileAndPath = keystorePath + keystoreName;
} else {
keystoreFileAndPath = keystorePath + "/" + keystoreName;
}
FileOutputStream fos = new FileOutputStream(keystoreFileAndPath);
keystore.store(fos, keystorePassword.toCharArray());
fos.close();
return true;
}
....
private KeyStore getMemoryKeystore(KeyStore customerKeystore, String certId, String customerKeystorePassword) {
KeyStore memoryKeystore = KeyStore.getInstance(KeyStore.getDefaultType());
memoryKeystore.load(null);
X509Certificate cert = (X509Certificate) customerKeystore.getCertificate(certId);
memoryKeystore.setCertificateEntry("cert-alias", cert);
Key key = customerKeystore.getKey(certId, customerKeystorePassword.toCharArray());
String caCertId = certId + "_CA";
X509Certificate caCert = (X509Certificate) customerKeystore.getCertificate(caCertId); // Pull CA Cert
memoryKeystore.setCertificateEntry("cacert-alias", caCert);
memoryKeystore.setKeyEntry("key-alias", key, AWS_IOT_INTERNAL_KEYSTORE_PASSWORD.toCharArray(), new Certificate[] { cert, caCert }); // <-- HERE!!
return memoryKeystore;
}
....
}
And before you connect and publish MQTT, get CSR and CA Cert that are chained within the KeyStore as below:
keystoreHelper = new MyKeystoreHelper(...);
if(keystoreHelper.isKeystorePresent(keystorePath, KEYSTORE_NAME)) {
keystore = keystoreHelper.getKeystore(CERTIFICATE_ID, keystorePath, KEYSTORE_NAME, KEYSTORE_PASSWORD);
} else {
// Create your own KeyStroe if it is not exist yet.
HashMap<String, String> directory = getDirectory(); // X.500 directory items for CSR
keystoreHelper.createKeystoreJIT(CERTIFICATE_ID, keystorePath, KEYSTORE_NAME, KEYSTORE_PASSWORD, directory);
keystore = keystoreHelper.getKeystore(CERTIFICATE_ID, keystorePath, KEYSTORE_NAME, KEYSTORE_PASSWORD);
}
Once you publish any message to the endpoint for the first time, AWS IoT Core will automatically create a "Thing".
I hope this helps you.
I'm creating an app to control a store, i'm trying to use a local server (192.168.0.56) through an open wifi.
There's a way to my app connect to my server using HTTPS and a self signed certificate?
I'm using retrofit, if its matter.
I tried a lot of tutorials on internet but no success, it always returns this message
Hostname '192.168.0.56' was not verified
to create the certificate i've used this code:
openssl genrsa -out san_server.key 2048
openssl req -new -key san_server.key -out san_server.csr -config openssl.cnf -subj "/C=BR/ST=Mato Grosso do Sul/L=Iguatemi/O=Talski/CN=192.168.0.56"
openssl req -text -noout -in san_server.csr
openssl genrsa -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -days 3650 -out rootCA.pem -config openssl.cnf -subj "/C=BR/ST=Mato Grosso do Sul/L=Iguatemi/O=Talski/CN=192.168.0.56"
openssl x509 -req -in san_server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out san_server-rootCA.crt -days 3649
openssl x509 -in rootCA.pem -outform der -out rootCA.der.crt
rootCA.der.crt was also installed in android
And openssl.cnf file:
HOME = .
RANDFILE = $ENV::HOME/.rnd
oid_section = new_oids
[ new_oids ]
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
dir = ./demoCA # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/cacert.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/cakey.pem# The private key
RANDFILE = $dir/private/.rand # private random number file
x509_extensions = usr_cert # The extentions to add to the cert
name_opt = ca_default # Subject Name options
cert_opt = ca_default # Certificate field options
default_days = 3650 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md = sha1 # which md to use.
preserve = no # keep passed DN ordering
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
####################################################################
[ req ]
default_bits = 1024
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
string_mask = nombstr
req_extensions = v3_req # The extensions to add to a certificate request
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = AU
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Some-State
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Internet Widgits Pty Ltd
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
unstructuredName = An optional company name
[ usr_cert ]
basicConstraints=CA:FALSE
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = IP:192.168.0.56
[ v3_ca ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer:always
basicConstraints = CA:true
[ crl_ext ]
authorityKeyIdentifier=keyid:always,issuer:always
[ proxy_cert_ext ]
basicConstraints=CA:FALSE
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer:always
proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
then created a TrustStore as explained in this https://stackoverflow.com/a/24007536/1001133
If you're using retrofit you can create a custom HTTP client (OkhttpClient/ApacheClient etc...) in order to configure your client and bind it to the retrofit client.
OkHttpClient okHttpClient = new OkHttpClient();
HostnameVerifier hostNameVerifier = new X509HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
try {
verifyHost(hostname);
return true;
} catch (SSLException e) {
e.printStackTrace();
return false;
}
}
#Override
public void verify(String host, String[] cns, String[] subjectAlts) throws SSLException {
verifyHost(host);
}
#Override
public void verify(String host, X509Certificate cert) throws SSLException {
verifyHost(host);
}
#Override
public void verify(String host, SSLSocket ssl) throws IOException {
verifyHost(host);
}
private void verifyHost(String sourceHost) throws SSLException {
if (!hostName.equals(sourceHost)) { // THIS IS WHERE YOU AUTHENTICATE YOUR EXPECTED host (IN THIS CASE 192.168.0.56)
throw new SSLException("Hostname '192.168.0.56' was not verified");
}
}
};
okHttpClient.setHostnameVerifier(hostNameVerifier);
OkClient okClient = new OkClient(okHttpClient);
RestAdapter restAdapter = new RestAdapter.Builder()
**.setClient(okClient)** //this is where u bind the httpClient
.build(); //make sure you specify endpoint, headerInterceptor etc ...
Hope this helps !