Best practices for a WiFi-connected device WITHOUT Internet connectivity - ssl

The company I work for makes a device that offers a Web-based setup and operation interface via WiFi. The device will typically be used out in the middle of nowhere, so the presence of an existing WiFi network cannot be assumed: the device's WiFi module therefore operates as an Access Point, and serves up the fancy HTML5 web app over HTTP (the only option available with the WiFi module I chose back in 2013, when this was originally implemented).
This worked great at first, but it's slowly falling apart as the Web evolves. Two problems in particular:
Part of the web app involves mapping, and of course it's quite useful to be able to show a "you are here" marker on a map - but Chrome already refuses to support the HTML5 Geolocation API over HTTP (without even an option to explicitly trust the page), and it looks like all the other browsers will follow suit.
The web app is pretty big (and the WiFi module pretty slow), so I use the HTML5 Application Cache feature to get effectively instant page loads after the initial use of the app. Unfortunately, major browsers are already refusing to allow this feature over HTTP, the feature is being deprecated anyway, and it's successor (Service Workers) is explicitly HTTPS-only.
I'm having to redo both the hardware and software of this feature, as the original WiFi module is no longer available. The modules available these days have lots more CPU power and storage (and cost a tenth as much), so it's now practical to do lots of things such as serving the web app over HTTPS. The advice I'm universally seeing for devices like this is to get a proper SSL certificate, but I don't see how that could possibly work in my case:
There will not normally be an Internet connection available when the device is actually in use, so the certificate couldn't be verified.
The device is accessed either by its IP address 192.168.1.1, or via the LLMNR/mDNS name ui.local. SSL certificates are not offered for either type of address.
I need this to work forever - there's no mechanism in place for updating the certificate in the device. Even 10 years (the longest validity that many self-signed certificate generators offer) would be inadequate; I refuse to build planned obsolescence into the device.
It could perhaps be made to sort of work by adding a DNS server to the device, basically making it a captive portal, so that it can be accessed via a normal URL that I can actually buy a SSL certificate for. However, I see lots of potential problems with this:
It fails if the user's computing device is set up with a static DNS server address (8.8.8.8 or whatever), rather than accepting one from DHCP.
It fails if the user actually has an Internet connection at the same time as the device's WiFi connection.
It fails permanently if DNSSEC ever catches on.
There's still the issue of certificate expiration.
That would appear to leave a self-signed certificate as the only workable option, despite all the advice to the contrary. One common objection to them is "you're teaching users to ignore valid security warnings"; I see your point, but what am I supposed to do instead?
Is there some approach I've overlooked, that would let my device continue to work with modern browsers as well as it did back in 2013?

I agree with you that accessing a device in a LAN without public address via HTTPS is tricky problem.
IMHO there should be a special TLS version of addressing those devices, however at the moment no such standard exists.
From my point of view only a self-signed certificate seems feasible. However when you are talking about "self-signed certificate generators" it to gives me a chill because you should never ever equip a a device with a pre-generated self-signed certificate!
This is one of the worst things you could ever do from a security perspective because pre-generated certificates and key pairs can always be extracted from the firmware and then used to attack one of your customers (Lenovo and other computer manufactures just learned that in the last years the hard way)!
When it comes to self-signed certificates there is only one way:
When the device first start-up wait until enough data has been processed (seeding) so that the random generator can generate secure random data.
Generate a public/private key pair using the generated random data
Generate a self-signed certificate using the previously generated key-pair. Using the right command you can set the validity end to any date you want.
Note that you can re-do step 3 at any time, e.g. when the user reconfigures the IP-address and you have to update that in the certificate. For self-developed clients (e.g. on Android or iOS) you could do public key pinning which would mean that the certificate does not have to be (re)installed.
Unfortunately for web browsers a new certificate even with the same public key means that you have to re-install the certificate as trusted.
Regarding the HTML5 Geolocation API: Can't you use this API via HTTPS? Mixed content is only a problem if you use HTTP resources in a HTTPS page, but the other way round there should not be a problem.
BTW: I found some slides that may be interesting for you, even if in that scenario Internet access is possible. May be you get some new ideas from it: https://www.w3.org/wiki/images/6/6c/TPAC2016_Local_Discovery_and_HTTPS.pdf

You can specify any expiration on a self-signed certificate that you want. It's a parameter to openssl (-days).
The following cert expires in 100 years:
openssl x509 -in localhost.pem -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
c2:a8:fc:a1:29:02:96:dd
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, ST = New York, L = New York, O = localhost, OU = Testing Domain, CN = localhost
Validity
Not Before: Apr 7 02:25:51 2018 GMT
Not After : Mar 14 02:25:51 2118 GMT
Subject: C = US, ST = New York, L = New York, O = localhost, OU = Testing Domain, CN = localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:96:89:c9:b4:8f:c0:2e:4c:92:15:cd:df:23:b2:
f1:6f:34:95:ca:e2:a4:c2:95:3f:1f:b3:50:56:16:
65:5a:1a:b9:99:6b:19:67:f0:13:54:76:23:4c:cd:
f5:2a:25:6c:d2:e0:67:e9:d5:34:0e:8f:2d:2b:dc:
04:3f:bb:e4:07:bd:a4:7a:ee:58:87:6b:cc:b7:1e:
79:fc:fc:bd:81:c7:e0:24:1d:91:14:50:70:5b:60:
13:ad:c7:eb:fb:67:3b:a9:e5:83:33:fb:ef:f4:26:
00:12:e3:af:e9:1e:e9:a2:5b:d1:98:3c:13:c0:30:
f0:13:9c:52:a3:b1:e7:3a:73:47:ce:ab:f9:5f:c4:
ff:74:1e:0c:86:ec:83:d6:b5:6d:36:31:00:26:97:
d8:74:39:cb:75:24:31:39:cc:e4:a1:78:38:92:07:
b4:a5:06:5a:8e:8b:0c:fa:7e:5e:55:7e:59:cf:f1:
1f:05:2e:e6:c2:6a:cf:4c:03:6a:66:b8:19:64:ae:
90:81:d9:28:37:2f:09:c1:b3:98:8a:bf:39:0a:0b:
23:db:55:79:02:83:fe:9d:be:ac:b8:3c:e5:1e:76:
5c:69:fe:f4:34:78:d4:36:82:0f:6e:c1:19:fe:39:
7f:fd:f0:4f:13:b6:2a:26:e6:ce:b0:fd:51:3d:38:
61:41
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
D6:DF:EB:FA:73:85:C9:22:AA:6D:79:E5:F9:16:01:2B:CC:E7:D8:D0
X509v3 Authority Key Identifier:
keyid:D6:DF:EB:FA:73:85:C9:22:AA:6D:79:E5:F9:16:01:2B:CC:E7:D8:D0
X509v3 Basic Constraints: critical
CA:TRUE
Signature Algorithm: sha256WithRSAEncryption
4f:ca:30:3f:fe:61:73:16:3f:a1:6d:5a:35:c1:b6:97:d6:63:
89:34:6e:05:e6:e6:84:7b:3b:b4:fc:89:65:7a:31:46:97:8f:
00:11:c7:61:97:86:b8:31:c7:a7:91:f7:c9:19:4e:0a:39:d7:
5e:95:52:17:92:8a:84:ce:6a:1b:1c:14:f2:15:18:62:78:07:
1e:d9:3c:5d:9c:28:65:42:bf:4f:61:0f:a3:86:e6:ff:38:34:
23:97:11:20:3c:5b:82:4a:ea:05:af:6d:5e:83:30:be:6d:64:
de:85:b8:bb:89:60:59:7a:c8:1f:ba:2d:02:04:34:89:65:32:
2c:10:f7:db:97:c3:ba:e2:ed:27:8a:bb:8d:9e:92:0a:d3:2e:
ad:9e:fb:15:fc:25:73:0d:e2:f9:45:3b:18:fd:89:e6:6b:31:
18:64:46:e2:dc:ad:e0:f3:f8:c1:b2:e6:93:bc:b3:db:9a:bc:
d3:58:38:68:e2:28:b4:6d:ca:07:d8:af:21:dc:10:bd:c0:75:
3f:b1:d2:24:96:5d:dd:a3:d2:e2:95:39:67:6b:06:bb:4d:91:
76:4f:9b:ce:7f:25:39:47:73:3e:fd:81:82:15:ac:6a:2c:cb:
82:76:04:b1:91:41:cf:8a:68:70:cd:7d:3f:2f:c9:1d:d5:a7:
3e:d0:3d:00
You can generate it with the following script:
#! /bin/bash
mkdir /tmp/scert 2>/dev/null
rm -r /tmp/scert/* 2>/dev/null
if [ $# -ne 1 ];
then
echo "Usage: scert <name>"
exit
fi
if [ -e "/etc/ssl/private/$1.key" ];
then
echo "/etc/ssl/private/$1.key already exists"
exit
fi
if [ -e "/etc/ssl/certs/$1.crt" ];
then
echo "/etc/ssl/certs/$1.crt already exists"
exit
fi
if [ -e "/etc/ssl/certs/$1.pem" ];
then
echo "/etc/ssl/certs/$1.pem already exists"
exit
fi
echo "[req]" > /tmp/scert/tmp.cnf
echo "default_bits = 2048" >> /tmp/scert/tmp.cnf
echo "prompt = no" >> /tmp/scert/tmp.cnf
echo "default_md = sha256" >> /tmp/scert/tmp.cnf
echo "distinguished_name = dn" >> /tmp/scert/tmp.cnf
echo "" >> /tmp/scert/tmp.cnf
echo "[dn]" >> /tmp/scert/tmp.cnf
echo "C=US" >> /tmp/scert/tmp.cnf
echo "ST=New York" >> /tmp/scert/tmp.cnf
echo "L=Rochester" >> /tmp/scert/tmp.cnf
echo "O=$1" >> /tmp/scert/tmp.cnf
echo "OU=Testing Domain" >> /tmp/scert/tmp.cnf
echo "emailAddress=spam#uce.gov" >> /tmp/scert/tmp.cnf
echo "CN = localhost" >> /tmp/scert/tmp.cnf
echo "authorityKeyIdentifier=keyid,issuer" > /tmp/scert/tmp.ext
echo "basicConstraints=CA:FALSE" >> /tmp/scert/tmp.ext
echo "keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment" >> /tmp/scert/tmp.ext
echo "subjectAltName = #alt_names" >> /tmp/scert/tmp.ext
echo "" >> /tmp/scert/tmp.ext
echo "[alt_names]" >> /tmp/scert/tmp.ext
echo "DNS.1 = localhost" >> /tmp/scert/tmp.ext
openssl genrsa -des3 -passout pass:xxxx -out /tmp/scert/tmp.pass.key 2048
openssl rsa -passin pass:xxxx -in "/tmp/scert/tmp.pass.key" -out "/tmp/scert/tmp.key"
openssl req -x509 -new -nodes -key /tmp/scert/tmp.key -subj "/C=US/ST=New York/L=New York/O=$1/OU=Testing Domain/CN=localhost" -sha256 -days 36500 -out /tmp/scert/$1.pem
openssl req -new -sha256 -nodes -out /tmp/scert/tmp.csr -newkey rsa:2048 -keyout /tmp/scert/$1.key -config <( cat /tmp/scert/tmp.cnf )
openssl x509 -req -in /tmp/scert/tmp.csr -CA /tmp/scert/$1.pem -CAkey /tmp/scert/tmp.key -CAcreateserial -out /tmp/scert/$1.crt -days 36500 -sha256 -extfile /tmp/scert/tmp.ext
if [ -e "/tmp/scert/$1.key" ];
then
sudo cp /tmp/scert/$1.key /etc/ssl/private
sudo chown root:ssl-cert /etc/ssl/private/$1.key
sudo chmod 640 /etc/ssl/private/$1.key
ls -al /etc/ssl/private/$1.key
else
echo "ERROR: /tmp/scert/$1.key not found"
fi
if [ -e "/tmp/scert/$1.crt" ];
then
sudo cp /tmp/scert/$1.crt /etc/ssl/certs
sudo chown root:root /etc/ssl/certs/$1.crt
sudo chmod 755 /etc/ssl/certs/$1.crt
ls -al /etc/ssl/certs/$1.crt
else
echo "ERROR: /tmp/scert/$1.crt not found"
fi
if [ -e "/tmp/scert/$1.pem" ];
then
sudo cp /tmp/scert/$1.pem /etc/ssl/certs
sudo chown root:root /etc/ssl/certs/$1.pem
sudo chmod 755 /etc/ssl/certs/$1.pem
ls -al /etc/ssl/certs/$1.pem
else
echo "ERROR: /tmp/scert/$1.pem not found"
fi
rm -r /tmp/scert/* 2>/dev/null
echo "DONE"

Related

Self-signed SLL certificate for Nextcloud Onion: "ERR_SSL_PROTOCOL_ERROR"

Context
After setting up a self-hosted nextcloud server on Ubuntu 22.10 over a tor domain, I created a self-signed SLL certificate using the script below:
Code
This script first
generates the certificate authority (CA) and SSL certificates, and then it adds the CA private key to: "/usr/local/share/ca-certificates/$ca_public_key_filename" and reloads the trusted ca certificates with:
sudo update-ca-certificates
It also adds the SSL prublic and private key and the full chain certificate into Nextcloud.
The fullchain.pem consists of the SSL certificate, followed by the CA certificate.
#!/usr/bin/env bash
# Here is the list of certificates and their description:
# First you create your own certificate authority.
CA_PRIVATE_KEY_FILENAME="ca-key.pem"
CA_PUBLIC_KEY_FILENAME="ca.pem"
# Same file as ca.pem except different file extension and content.
CA_PUBLIC_CERT_FILENAME="ca.crt"
# Then you create a SSL certificate.
SSL_PRIVATE_KEY_FILENAME="cert-key.pem"
# Then create a sign-request (for your own CA to sign your own SSL certificate)
CA_SIGN_SSL_CERT_REQUEST_FILENAME="cert.csr"
SIGNED_DOMAINS_FILENAME="extfile.cnf"
# Then create the signed public SSL cert.
SSL_PUBLIC_KEY_FILENAME="cert.pem"
# Then merge the CA and SLL cert into one.
MERGED_CA_SSL_CERT_FILENAME="fullchain.pem"
setup_tor_ssl() {
local onion_address="$1"
# Create domains accepted by certificate.
local domains
#domains="DNS:$onion_address,IP:127.0.0.1"
#domains="DNS:localhost,IP:$onion_address" # IP onion does not work
#domains="DNS:*.$onion_address" # Does not work.
#domains="DNS:$onion_address" # Does not work.
domains="DNS:localhost,DNS:$onion_address" # Works for localhost
echo "domains=$domains.end_without_space"
delete_target_files
# Generate and apply certificate.
generate_ca_cert "$CA_PRIVATE_KEY_FILENAME" "$CA_PUBLIC_KEY_FILENAME"
generate_ssl_certificate "$CA_PUBLIC_KEY_FILENAME" "$CA_PRIVATE_KEY_FILENAME" "$CA_SIGN_SSL_CERT_REQUEST_FILENAME" "$SIGNED_DOMAINS_FILENAME" "$SSL_PUBLIC_KEY_FILENAME" "$SSL_PRIVATE_KEY_FILENAME" "$domains"
verify_certificates "$CA_PUBLIC_KEY_FILENAME" "$SSL_PUBLIC_KEY_FILENAME"
merge_ca_and_ssl_certs "$SSL_PUBLIC_KEY_FILENAME" "$CA_PUBLIC_KEY_FILENAME" "$MERGED_CA_SSL_CERT_FILENAME"
install_the_ca_cert_as_a_trusted_root_ca "$CA_PUBLIC_KEY_FILENAME" "$CA_PUBLIC_CERT_FILENAME"
add_certs_to_nextcloud "$SSL_PUBLIC_KEY_FILENAME" "$SSL_PRIVATE_KEY_FILENAME" "$MERGED_CA_SSL_CERT_FILENAME"
}
generate_ca_cert() {
local ca_private_key_filename="$1"
local ca_public_key_filename="$2"
# Generate RSA
openssl genrsa -aes256 -out "$ca_private_key_filename" 4096
# Generate a public CA Cert
openssl req -new -x509 -sha256 -days 365 -key "$ca_private_key_filename" -out "$ca_public_key_filename"
}
generate_ssl_certificate() {
local ca_public_key_filename="$1"
local ca_private_key_filename="$2"
local ca_sign_ssl_cert_request_filename="$3"
local signed_domains_filename="$4"
local ssl_public_key_filename="$5"
local ssl_private_key_filename="$6"
local domains="$7"
# Example supported domains:
# DNS:your-dns.record,IP:257.10.10.1
# Create a RSA key
openssl genrsa -out "$ssl_private_key_filename" 4096
# Create a Certificate Signing Request (CSR)
openssl req -new -sha256 -subj "/CN=yourcn" -key "$ssl_private_key_filename" -out "$ca_sign_ssl_cert_request_filename"
# Create a `extfile` with all the alternative names
echo "subjectAltName=$domains" >>"$signed_domains_filename"
# optional
#echo extendedKeyUsage = serverAuth >> "$ca_sign_ssl_cert_request_filename"
# Create the public SSL certificate.
openssl x509 -req -sha256 -days 365 -in "$ca_sign_ssl_cert_request_filename" -CA "$ca_public_key_filename" -CAkey "$ca_private_key_filename" -out "$ssl_public_key_filename" -extfile "$signed_domains_filename" -CAcreateserial
}
verify_certificates() {
local ca_public_key_filename="$1"
local ssl_public_key_filename="$2"
openssl verify -CAfile "$ca_public_key_filename" -verbose "$ssl_public_key_filename"
}
merge_ca_and_ssl_certs() {
local ssl_public_key_filename="$1"
local ca_public_key_filename="$2"
local merged_ca_ssl_cert_filename="$3"
cat "$ssl_public_key_filename" >"$merged_ca_ssl_cert_filename"
cat "$ca_public_key_filename" >>"$merged_ca_ssl_cert_filename"
}
install_the_ca_cert_as_a_trusted_root_ca() {
local ca_public_key_filename="$1"
local ca_public_cert_filename="$2"
# The file in the ca-certificates dir must be of extension .crt:
openssl x509 -outform der -in "$ca_public_key_filename" -out "$ca_public_cert_filename"
# First remove any old cert if it existed.
sudo rm "/usr/local/share/ca-certificates/$ca_public_cert_filename"
sudo update-ca-certificates
# TODO: Verify target directory exists.
# On Debian & Derivatives:
#- Move the CA certificate (`"$ca_private_key_filename"`) into `/usr/local/share/ca-certificates/ca.crt`.
sudo cp "$ca_public_cert_filename" "/usr/local/share/ca-certificates/$ca_public_cert_filename"
# TODO: Verify target file exists.
# TODO: Verify target file MD5sum.
# Update the Cert Store with:
sudo update-ca-certificates
}
add_certs_to_nextcloud() {
local ssl_public_key_filename="$1"
local ssl_private_key_filename="$2"
local merged_ca_ssl_cert_filename="$3"
# First copy the files into nextcloud.
# Source: https://github.com/nextcloud-snap/nextcloud-snap/issues/256
# (see nextcloud.enable-https custom -h command).
#sudo cp ca.pem /var/snap/nextcloud/current/ca.pem
sudo cp "$ssl_public_key_filename" /var/snap/nextcloud/current/"$ssl_public_key_filename"
sudo cp "$ssl_private_key_filename" /var/snap/nextcloud/current/"$ssl_private_key_filename"
sudo cp "$merged_ca_ssl_cert_filename" /var/snap/nextcloud/current/"$merged_ca_ssl_cert_filename"
# CLI sudo /snap/bin/nextcloud.enable-https custom Says:
sudo /snap/bin/nextcloud.enable-https custom "/var/snap/nextcloud/current/$ssl_public_key_filename" "/var/snap/nextcloud/current/$ssl_private_key_filename" "/var/snap/nextcloud/current/$merged_ca_ssl_cert_filename"
}
delete_target_files() {
rm "$CA_PRIVATE_KEY_FILENAME"
rm "$CA_PUBLIC_CERT_FILENAME"
rm "$CA_PUBLIC_KEY_FILENAME"
rm "$SSL_PRIVATE_KEY_FILENAME"
rm "$CA_SIGN_SSL_CERT_REQUEST_FILENAME"
rm "$SIGNED_DOMAINS_FILENAME"
rm "$SSL_PUBLIC_KEY_FILENAME"
rm "$MERGED_CA_SSL_CERT_FILENAME"
sudo rm "/usr/local/share/ca-certificates/$CA_PUBLIC_KEY_FILENAME"
sudo rm "/usr/local/share/ca-certificates/$CA_PUBLIC_CERT_FILENAME"
sudo rm "/var/snap/nextcloud/current/$SSL_PUBLIC_KEY_FILENAME"
sudo rm "/var/snap/nextcloud/current/$SSL_PRIVATE_KEY_FILENAME"
sudo rm "/var/snap/nextcloud/current/$MERGED_CA_SSL_CERT_FILENAME"
}
Output
The output of this script can be read as:
$src/main.sh -h
domains=DNS:some_onion.onion,IP:127.0.0.1.end_without_space
rm: cannot remove 'ca.pem': No such file or directory
rm: cannot remove 'cert.csr': No such file or directory
rm: cannot remove 'extfile.cnf': No such file or directory
rm: cannot remove 'cert.pem': No such file or directory
rm: cannot remove 'fullchain.pem': No such file or directory
rm: cannot remove '/usr/local/share/ca-certificates/ca.pem': No such file or directory
Generating RSA private key, 4096 bit long modulus (2 primes)
................................................................................................................................................................................++++
...................................................................................................................................................................................................................................++++
e is 65537 (0x010001)
Enter pass phrase for ca-key.pem:
Verifying - Enter pass phrase for ca-key.pem:
Enter pass phrase for ca-key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:so
State or Province Name (full name) [Some-State]:state3
Locality Name (eg, city) []:locality3
Organization Name (eg, company) [Internet Widgits Pty Ltd]:org3
Organizational Unit Name (eg, section) []:orgunit3
Common Name (e.g. server FQDN or YOUR name) []:cn3
Email Address []:email3#email.com
Generating RSA private key, 4096 bit long modulus (2 primes)
...................................................................++++
.............................................++++
e is 65537 (0x010001)
Signature ok
subject=CN = yourcn
Getting CA Private Key
Enter pass phrase for ca-key.pem:
cert.pem: OK
Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
Processing triggers for ca-certificates-java (20220719) ...
done.
Updating Mono key store
Mono Certificate Store Sync - version 6.8.0.105
Populate Mono certificate store from a concatenated list of certificates.
Copyright 2002, 2003 Motus Technologies. Copyright 2004-2008 Novell. BSD licensed.
Importing into legacy system store:
I already trust 124, your new list has 124
Import process completed.
Importing into BTLS system store:
I already trust 124, your new list has 124
Import process completed.
Done
done.
Installing custom certificate... done
Restarting apache... done
Error Message
After running the script successfully, I can manually import the ca.crt into brave at: brave://settings/certificates This ensures https works for https://localhost:81 . However, when I open the tor browser in brave, and visit the some_onion.onion it returns:
This site can’t provide a secure connection
some_onion.onion sent an invalid response.
ERR_SSL_PROTOCOL_ERROR
Question
How can I ensure the certificate is trusted on both the some_onion.onion link, as well as on localhost?
Doubt
I am unsure whether:
echo "subjectAltName=DNS:some_onion_link.onion"
is permitted. for an SSL certificate. I wonder why the tor version of Brave does not show why the certificate is not trusted.

How to verify a Microsoft certificate

This is the certificate https://gist.github.com/larytet/2fb447e875831577584592cd99980fd1 (x5t VjWIUjS5JS3eAFdm2dnydlZfY-I)
I am doing
openssl verify -verbose -x509_strict certificate.pen
I am getting
CN = estsclient.coreauth.outlook.com
error 20 at 0 depth lookup: unable to get local issuer certificate
error certificate.pem: verification failed
Where do I find the certificate, the whole chain or the root which should be installed in my system?
You need to provide the CA certificate, and most real CAs will list locations where its certificate can be found in an extension in each certificate they issue.
With OpenSSL, you can view this extension:
openssl x509 -text -noout < certificate.pem
Look for the "Authority Information Access extension", and its "CA Issuers" field to find the URL and download the certificate from Microsoft.
Because this file is encoded with DER, it needs to be transcoded to PEM for use with openssl verify:
openssl x509 -inform der < Microsoft\ IT\ TLS\ CA\ 2.crt > Microsoft\ IT\ TLS\ CA\ 2.pem
Because you just downloaded this file from who knows where over HTTP, you need some way to verify its authenticity.
You'll notice that it too lists an issuer, so you can perform this process recursively to obtain the entire certificate chain back to a root certificate that you already trust. Usually, we trust the certificates that come pre-installed on our systems. But, in theory, an attacker could have compromised that set, so people sometimes do find out-of-band means to verify their root CA certificates. What's appropriate for you depends on your application.
The chain of certificates that you download on your way to the trust anchor are "intermediate" certificates; you don't have to trust them directly, because you'll be verifying a chain starting with one of the anchors on your system.
Concatenate the PEM-encoded certificates, including headers and footers, together in a single file of untrusted certificates. In my case, the "Baltimore CyberTrust Root" certificate that issued the "Microsoft IT TLS CA 2" intermediate certificate is pre-installed as a root CA on my system, so I only have to download the Microsoft certificate, and it's the only one in my file of "untrusted" certificates.
Now you have the necessary information to attempt your original command:
openssl verify --verbose -untrusted Microsoft\ IT\ TLS\ CA\ 2.pem -x509_strict certificate.pem
In case anyone finds this question I ended up with something like this + lot of comment
RUN curl --silent https://outlook.com/autodiscover/metadata/json/1 > ./outlook.com.autodiscover.metadata.json.1
RUN pem_file=certificate.pem \
&& echo "-----BEGIN CERTIFICATE-----" > $pem_file \
&& cat ./outlook.com.autodiscover.metadata.json.1 | jq --raw-output '.keys[0].keyvalue.value' >> $pem_file \
&& echo "-----END CERTIFICATE-----" >> $pem_file \
&& cat $pem_file \
&& openssl x509 -text -noout < $pem_file | grep "CA Issuers" \
&& curl https://cacerts.digicert.com/BaltimoreCyberTrustRoot.crt.pem > rootCA.pem \
&& curl http://www.microsoft.com/pki/mscorp/Microsoft%20IT%20TLS%20CA%202.crt | openssl x509 -inform der >> rootCA.pem \
&& curl https://cacerts.digicert.com/DigiCertCloudServicesCA-1.crt | openssl x509 -inform der >> rootCA.pem \
&& cat rootCA.pem \
&& cat certificate.pem
RUN pem_file=certificate.pem && openssl verify -verbose -x509_strict -untrusted rootCA.pem $pem_file

x509 error when trying to login to a trusted (?) docker registry

I have set up a docker registry using harbor.
I have copied the appropriate certificates in /usr/share/local/ca-certificates and run sudo update-ca-certificates with success. (indicated the number of newly certs added).
When trying to login to the specific registry:
ubuntu#master1:/home/vagrant$ docker login my.registry.url
Username: pkaramol
Password:
Error response from daemon: Get https://my.registry.url/v2/: x509: certificate signed by unknown authority
However the following test succeeds:
openssl s_client -connect my.registry.url:443 -CApath /etc/ssl/certs/
...coming back with a lot of verbose output, the certificate itself and ending in :
Verify return code: 0 (ok)
curl also succeeds to the above https link (it fails when the site is not trusted).
Any suggestions?
If you read the documentation
Use self-signed certificates
Warning: Using this along with basic authentication requires to also trust the certificate into the OS cert store for some versions of docker (see below)
This is more secure than the insecure registry solution.
Generate your own certificate:
$ mkdir -p certs
$ openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
-x509 -days 365 -out certs/domain.crt
Be sure to use the name myregistrydomain.com as a CN.
Use the result to start your registry with TLS enabled.
Instruct every Docker daemon to trust that certificate. The way to do this depends on your OS.
Linux: Copy the domain.crt file to /etc/docker/certs.d/myregistrydomain.com:5000/ca.crt on every Docker host. You do not need to restart Docker.
See below link for more details
https://docs.docker.com/registry/insecure/#use-self-signed-certificates

Trouble getting a self-signed cert working in Postman

I'm finally getting into using SSL on my personal sites, so I started by trying to make a multi-domain self signed cert for my local development (to handle api.mydomain.local, www.mydomain.local, and mydomain.local). I don't know if this was my first mistake, but...
As I couldn't find a single encompassing guide, I started by using two tutorials (from EasyEngine and DeveloperSide) to create my cert and install it on my host (Win10). I then used a DigitalOcean guide to figure out how to setup my Apache on my dev server (a Ubuntu VM); up to there, no big trouble, other than some minor issues caused by working from multiple guides at the same time.
I go ahead and try to hit my api in Chrome, it gives me an untrusted certificate value as expected, I pass and it works. As far as I know, this means the cert worked? However, when I try to hit my api in Postman, I get an error that indicates it can't accept an untrusted cert, which is fine, as it has a tutorial on how to fix that. However, it still doesn't work. I can't figure out what else to do to fix this, am I on the right track? Is my cert completely borked? Did I make a core mistake in trying to do a multi-domain cert?
One thing I did notice is that in the Dev Tools security tab, it says
Subject Alternative Name missing
So I'm not sure if that means my alt names aren't working, but if they weren't, it wouldn't try to load the certificate when I hit it in Chrome, right?
I had a similar issue while writing an article for my website on SSL certificates. So i wrote shell script for the same
#!/bin/bash
CERT_COMPANY_NAME=${CERT_COMPANY_NAME:=Tarun Lalwani}
CERT_COUNTRY=${CERT_COUNTRY:=IN}
CERT_STATE=${CERT_STATE:=DELHI}
CERT_CITY=${CERT_CITY:=DELHI}
CERT_DIR=${CERT_DIR:=certs}
ROOT_CERT=${ROOT_CERT:=rootCA.pem}
ROOT_CERT_KEY=${ROOT_CERT_KEY:=rootCA.key.pem}
# make directories to work from
mkdir -p $CERT_DIR
create_root_cert(){
# Create your very own Root Certificate Authority
openssl genrsa \
-out $CERT_DIR/$ROOT_CERT_KEY \
2048
# Self-sign your Root Certificate Authority
# Since this is private, the details can be as bogus as you like
openssl req \
-x509 \
-new \
-nodes \
-key ${CERT_DIR}/$ROOT_CERT_KEY \
-days 1024 \
-out ${CERT_DIR}/$ROOT_CERT \
-subj "/C=$CERT_COUNTRY/ST=$CERT_STATE/L=$CERT_CITY/O=$CERT_COMPANY_NAME Signing Authority/CN=$CERT_COMPANY_NAME Signing Authority"
}
create_domain_cert()
{
local FQDN=$1
local FILENAME=${FQDN/\*/wild}
# Create a Device Certificate for each domain,
# such as example.com, *.example.com, awesome.example.com
# NOTE: You MUST match CN to the domain name or ip address you want to use
openssl genrsa \
-out $CERT_DIR/${FILENAME}.key \
2048
# Create a request from your Device, which your Root CA will sign
if [[ ! -z "${SAN}" ]]; then
openssl req -new \
-key ${CERT_DIR}/${FILENAME}.key \
-out ${CERT_DIR}/${FILENAME}.csr \
-subj "/C=${CERT_COUNTRY}/ST=${CERT_STATE}/L=${CERT_CITY}/O=$CERT_COMPANY_NAME/CN=${FQDN}" \
-reqexts san_env -config <(cat /etc/ssl/openssl.cnf <(cat ./openssl-san.cnf))
else
openssl req -new \
-key ${CERT_DIR}/${FILENAME}.key \
-out ${CERT_DIR}/${FILENAME}.csr \
-subj "/C=${CERT_COUNTRY}/ST=${CERT_STATE}/L=${CERT_CITY}/O=$CERT_COMPANY_NAME/CN=${FQDN}"
fi
# Sign the request from Device with your Root CA
if [[ ! -z "${SAN}" ]]; then
openssl x509 \
-sha256 \
-req -in $CERT_DIR/${FILENAME}.csr \
-CA $CERT_DIR/$ROOT_CERT \
-CAkey $CERT_DIR/$ROOT_CERT_KEY \
-CAcreateserial \
-out $CERT_DIR/${FILENAME}.crt \
-days 500 \
-extensions san_env \
-extfile openssl-san.cnf
else
openssl x509 \
-sha256 \
-req -in $CERT_DIR/${FILENAME}.csr \
-CA $CERT_DIR/$ROOT_CERT \
-CAkey $CERT_DIR/$ROOT_CERT_KEY \
-CAcreateserial \
-out $CERT_DIR/${FILENAME}.crt \
-days 500
fi
}
METHOD=$1
ARGS=${*:2}
echo "Called with $METHOD and $ARGS"
if [ -z "${METHOD}" ]; then
echo "Usage ./sslcerts.sh [create_root_cert|create_domain_cert] <args>"
echo "Below are the environment variabls you can use:"
echo "CERT_COMPANY_NAME=Company Name"
echo "CERT_COUNTRY=Country"
echo "CERT_STATE=State"
echo "CERT_CITY=City"
echo "CERT_DIR=Directory where certificate needs to be genereated"
echo "ROOT_CERT=Name of the root cert"
echo "ROOT_CERT_KEY=Name of root certificate key"
else
${METHOD} ${ARGS}
fi
You can change the environment variables on the TOP and generate a self-signed certificate using below
$ SAN=DNS.1:*.tarunlalwani.com,DNS.2:tarunlalwani.com ./sslcerts.sh create_domain_cert '*.tarunlalwani.com'
Edit 1
Earlier browsers use to rely on FQDN, but now some of them have started using SAN which is "Subject Alternative Name". Generally openssl doesn't come up v3 extensions configured. SAN is a part of the v3 extensions. So when you generated a self signed certificated it has the correct FQDN (Full qualified domain name) but not SAN. Chrome will show error for these certificates but you will see firefox working fine.
PS: Taken from article http://tarunlalwani.com/post/self-signed-certificates-trusting-them/

HTTPS inspection on my server

I have been trying to inspect all the traffic going through my machine. I have a server directly connected to Internet. And I would like to log all the youtube request made on internet with the URL.
As youtube is based on SSL, so I must need to inspect the HTTPS traffic. I have read it somewhere that I must need to create MITM attack on my own server in order to view the HTTPS request. I have followed following steps in order to create a certificate I own.
1 - Generate a 2048 bit RSA Key: openssl genrsa -des3 -out private.pem
2048
2 - Export the RSA Public Key to a File: openssl rsa -in private.pem
-outform PEM -pubout -out public.pem
3 - Check The public key File (Certificate) Now: less public.pem
4 - Export the RSA Public Key to a File: openssl rsa -in private.pem
-out private_unencrypted.pem -outform PEM -pubout
5 - Check The Private File Now: less private.pem
6 - Copied certificate into certificate directory
7 - Configure certificate by using following command: sudo dpkg-reconfigure ca-certificates
In the end executed all the possible ways available:
mitmproxy -T
Above command open a console application and I accessed all the HTTPs sites but no effect on this window.
And
sudo ssldump -Ad -k cert.pem -p password -i wlo1
This command just printed some handshake stuff in console and after that terminated. But, nothing is related to URL.
And
sudo iptables -t nat -A PREROUTING -p tcp --destination-port 443 -j REDIRECT --to-port 1024
sudo sslstrip -l 1024
This commands keep on listening but, nothing comes out as a result in sslstrip.log file.
I am using all these things with Ubuntu 15 and want to dump ssl request in transparent mode i.e. without setting up proxy on client's machine.