I am able to get the certificate loaded properly and can access my server (baby steps...) My problem now is that the parameters ("username=admin&password=admin") are not getting into the server (the request is coming as null). Here is my Android code (some of which) I got from here:
String host = "turbo";
int port = 8081;
String command = "get_status";
String user = "admin";
String password = "admin";
HttpsURLConnection connection = null;
try {
Certificate ca;
String keyStoreType;
KeyStore keyStore;
String tmfAlgorithm;
TrustManagerFactory tmf;
Scanner scanner;
boolean hasInput;
/**
* Set up certificate stuff first
*/
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream ins = myContext.getResources().openRawResource(
myContext.getResources().getIdentifier("server_crt", "raw",
myContext.getPackageName()));
BufferedInputStream caInput = new BufferedInputStream(ins);
ca = cf.generateCertificate(caInput);
caInput.close();
keyStoreType = KeyStore.getDefaultType();
keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
URL url = new URL(String.format("https://%s:%d/test/%s", host, port, command));
connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(context.getSocketFactory());
connection.setReadTimeout(1500);
connection.setConnectTimeout(1500);
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
DataOutputStream os = new DataOutputStream(connection.getOutputStream());
os.writeBytes("username=admin&password=admin");
String b = getPostDataString(params);
os.flush();
os.close();
I had to change my Flask run method to have host='0.0.0.0' and now I am getting connected with my Android code below, but I am having other issues: I am having problems getting the parameters across (username and password).
On the server side, I am getting an error where a parameter (username) is null.
I have tried this also:
Map<String,Object> params = new LinkedHashMap<>();
params.put("username", user);
params.put("password", password);
StringBuilder postData = new StringBuilder();
for (Map.Entry<String,Object> param : params.entrySet()) {
if (postData.length() != 0) postData.append('&');
postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
connection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
connection.setDoOutput(true);
connection.getOutputStream().write(postDataBytes);
connection.setReadTimeout(30000);
connection.setConnectTimeout(30000);
int responseCode = connection.getResponseCode();
But the responseCode is 400 and I am getting the same error on the server (username not defined) Any suggestions?
app.run(debug=server_debug, ssl_context=context, host='0.0.0.0', port=server_port)
I am having problems connecting via HTTPS from my Android app with a self-signed certification.
I created the create_key.cfg:
[req]
default_bits=2048
prompt=no
default_md=sha256
x509_extensions=v3_req
#req_extensions=req_ext
distinguished_name=dn
[dn]
C=US
ST=Florida
L=Satellite Beach
O=ThompCo, Inc
OU=turbo
emailAddress=Jordan@ThompCo.com
CN=turbo
[v3_req]
subjectAltName=@alt_names
[alt_names]
DNS.1=turbo
DNS.2=turbo.thompco.com
DNS.3=thompco.com
Then I ran the following commands:
openssl req -x509 -nodes -days 730 -newkey rsa:2048 -keyout server.key -out server.crt -config create_key.cfg -sha256
openssl x509 -in server.crt -out server.pem -outform PEM
which creates the files:
server.crt server.key server.pem
When I access the site with Chrome, I get the correct certificate information (obviously there is a warning that the certificate is not secure)
When I run my test python scripts (which use urllib2) everything works as expected.
I tried running straight curl:
curl https://turbo:8081
But I got this error:
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
I tried adding the crt file to /usr/lib/ssl/certs as suggested here but it didn't help (perhaps this is the root of the problem?)
I am dabbling (read "I have no idea what I am doing") in Android and have written (with the help of Google and many fine developers around the world) the following (Note that I put server.pem into the res/raw folder):
package com.thompco.test;
import android.content.Context;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Scanner;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
class DoCurl extends Thread {
Context myParentContext;
public DoCurl(Context context) {
myParentContext = context;
}
public void run() {
String host = "turbo";
int port = 8081;
HttpsURLConnection connection = null;
String command = "get_status";
String http = "https";
String user = "admin";
String password = "admin";
try {
Certificate ca;
String keyStoreType;
KeyStore keyStore;
String tmfAlgorithm;
TrustManagerFactory tmf;
SSLContext context;
URL url;
InputStream in;
Scanner scanner;
boolean hasInput;
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream ins = myParentContext.getResources().openRawResource(
myParentContext.getResources().getIdentifier("server",
"raw", myParentContext.getPackageName()));
BufferedInputStream caInput = new BufferedInputStream(ins);
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
keyStoreType = KeyStore.getDefaultType();
keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
url = new URL(String.format("%s://%s:%d/test/%s", http, host, port, command));
connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(context.getSocketFactory());
connection.setRequestProperty("username", user);
connection.setRequestProperty("password", password);
connection.setReadTimeout(30000);
connection.setConnectTimeout(30000);
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.connect();
if (connection.getResponseCode() == 200) {
// Success
// Further processing here
} else {
// Error handling code goes here
}
in = connection.getInputStream();
scanner = new Scanner(in);
scanner.useDelimiter("\\A");
hasInput = scanner.hasNext();
if (hasInput) {
String tmp = scanner.next();
}
} catch (Exception e) {
Exception blah = e;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
}
When this runs, it throws a java.security.cert.CertPathValidatorException: Trust anchor for certification path not found when trying to connect.
My goal is to be able to deploy this device (currently running Flask) and be able to access it from an Android phone on my local network. I don't want to install a truly trusted certificate if I can get away with it.
The server happens to be running in python on a windows machine. It works fine with my curl tests and I know that that is not the best way to do this, but I am just testing the Android app for now.
I went back to my Python test code and confirmed that I am connecting correctly (note that I am using the appropriate .crt file) which should validate the validity of the self-signed certificate:
def send_curl(command, host, port, data, use_ssh=True):
logger = get_logger()
logger.debug("host:{}, port:{}".format(host, port))
context = ssl.create_default_context()
context.load_verify_locations("../keys/server.crt")
url = '{}://{}:{}/test/{}'.format("https", host, port, command)
for k, v in data.items():
data[k] = str(v)
data = json.dumps(data)
logger.debug("URL is {}".format(url))
logger.debug("data is {}".format(data))
req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
try:
rtn = urllib2.urlopen(req, context=context)
pp = pprint.PrettyPrinter()
pp.format = my_safe_repr
print "Success:" + str(rtn.code)
pp.pprint(data)
except urllib2.HTTPError as err:
print str(err) + ":"
print err.read()
data = None
return data