Initial commit

This commit is contained in:
2021-05-27 13:15:46 +03:00
commit d121e8417c
66 changed files with 2782 additions and 0 deletions

@@ -0,0 +1,2 @@
pip3 install --upgrade git+http://git.k-space.ee/pinecrypt/pinecrypt-client.git
certidude provision {{ authority.namespace }}

@@ -0,0 +1,98 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- https://developer.apple.com/library/content/featuredarticles/iPhoneConfigurationProfileRef/Introduction/Introduction.html -->
<key>PayloadDisplayName</key>
<string>{{ gateway }}</string>
<key>PayloadDescription</key>
<string>IPSec IKEv2 VPN connection via {{ gateway }}</string>
<!-- This is a reverse-DNS style unique identifier used to detect duplicate profiles -->
<key>PayloadIdentifier</key>
<string>{{ gateway }}</string>
<key>PayloadUUID</key>
<string>{{ service_uuid }}</string>
<key>PayloadType</key>
<string>Configuration</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadContent</key>
<array>
<dict>
<key>PayloadIdentifier</key>
<string>{{ gateway }}.conf1</string>
<key>PayloadUUID</key>
<string>{{ conf_uuid }}</string>
<key>PayloadType</key>
<string>com.apple.vpn.managed</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>UserDefinedName</key>
<string>{{ gateway }}</string>
<key>VPNType</key>
<string>IKEv2</string>
<key>IKEv2</key>
<dict>
<key>RemoteAddress</key>
<string>{{ gateway }}</string>
<key>RemoteIdentifier</key>
<string>{{ gateway }}</string>
<key>LocalIdentifier</key>
<string>{{ common_name }}</string>
<key>ServerCertificateIssuerCommonName</key>
<string>{{ authority.certificate.common_name }}</string>
<key>ServerCertificateCommonName</key>
<string>{{ gateway }}</string>
<key>AuthenticationMethod</key>
<string>Certificate</string>
<key>IKESecurityAssociationParameters</key>
<dict>
<key>EncryptionAlgorithm</key>
<string>AES-256</string>
<key>IntegrityAlgorithm</key>
<string>SHA2-384</string>
<key>DiffieHellmanGroup</key>
<integer>14</integer>
</dict>
<key>ChildSecurityAssociationParameters</key>
<dict>
<key>EncryptionAlgorithm</key>
<string>AES-128-GCM</string>
<key>IntegrityAlgorithm</key>
<string>SHA2-256</string>
<key>DiffieHellmanGroup</key>
<integer>14</integer>
</dict>
<key>EnablePFS</key>
<integer>1</integer>
<key>PayloadCertificateUUID</key>
<string>{{ p12_uuid }}</string>
</dict>
</dict>
<dict>
<key>PayloadIdentifier</key>
<string>{{ common_name }}</string>
<key>PayloadUUID</key>
<string>{{ p12_uuid }}</string>
<key>PayloadType</key>
<string>com.apple.security.pkcs12</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadContent</key>
<data>{{ p12 }}</data>
</dict>
<dict>
<key>PayloadIdentifier</key>
<string>{{ authority.certificate.common_name }}</string>
<key>PayloadUUID</key>
<string>{{ ca_uuid }}</string>
<key>PayloadType</key>
<string>com.apple.security.root</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadContent</key>
<data>{{ ca }}</data>
</dict>
</array>
</dict>
</plist>

@@ -0,0 +1,29 @@
[connection]
certidude managed = true
id = {{ session.service.title }}
uuid = {{ uuid }}
type = vpn
[vpn]
service-type = org.freedesktop.NetworkManager.openvpn
connection-type = tls
cert-pass-flags 0
tap-dev = no
remote-cert-tls = server
remote = {{ authority.namespace }}
key = {% if key_path %}{{ key_path }}{% else %}/etc/certidude/authority/{{ authority.namespace }}/host_key.pem{% endif %}
cert = {% if certificate_path %}{{ certificate_path }}{% else %}/etc/certidude/authority/{{ authority.namespace }}/host_cert.pem{% endif %}
ca = {% if authority_path %}{{ authority_path }}{% else %}/etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem{% endif %}
tls-cipher = {{ authority.openvpn.tls_cipher }}
cipher = {{ authority.openvpn.cipher }}
auth = {{ authority.openvpn.auth }}
{% if port %};port = {{ port }}{% else %};port = 1194{% endif %}
{% if not proto or not proto.startswith('tcp') %};{% endif %}proto-tcp = yes
[ipv4]
# Route only pushed subnets to tunnel
never-default = true
method = auto
[ipv6]
method = auto

@@ -0,0 +1,23 @@
[connection]
certidude managed = true
id = {{ session.service.title }}
uuid = {{ uuid }}
type = {{ vpn }}
[vpn]
service-type = org.freedesktop.NetworkManager.strongswan
encap = no
virtual = yes
method = key
ipcomp = no
address = {{ authority.namespace }}
userkey = {% if key_path %}{{ key_path }}{% else %}/etc/certidude/authority/{{ authority.namespace }}/host_key.pem{% endif %}
usercert = {% if certificate_path %}{{ certificate_path }}{% else %}/etc/certidude/authority/{{ authority.namespace }}/host_cert.pem{% endif %}
certificate = {% if authority_path %}{{ authority_path }}{% else %}/etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem{% endif %}
ike = {{ authority.strongswan.ike }}
esp = {{ authority.strongswan.esp }}
proposal = yes
[ipv4]
method = auto
;route1 = 0.0.0.0/0

@@ -0,0 +1,31 @@
server {
listen 80;
server_name {{ common_name }};
rewrite ^ https://{{ common_name }}\$request_uri?;
}
server {
root /var/www/html;
add_header X-Frame-Options "DENY";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
listen 443 ssl;
server_name $NAME;
client_max_body_size 10G;
ssl_certificate {{certificate_path}};
ssl_certificate_key {{key_path}};
ssl_client_certificate {{authority_path}};
# Uncomment following to enable mutual authentication with certificates
#ssl_crl {{revocations_path}};
#ssl_verify_client on;
location ~ \.php\$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param REMOTE_USER \$ssl_client_s_dn_cn;
include fastcgi_params;
}
}

@@ -0,0 +1,3 @@
[Timer]
OnCalendar=*:0/15
Persistent=true

@@ -0,0 +1,31 @@
client
nobind
remote {{ authority.namespace }} 1194 udp
remote {{ authority.namespace }} 443 tcp
proto udp
port 1194
tls-version-min {{ authority.openvpn.tls_version_min }}
tls-cipher {{ authority.openvpn.tls_cipher }}
cipher {{ authority.openvpn.cipher }}
auth {{authority.openvpn.auth }}
mute-replay-warnings
reneg-sec 0
remote-cert-tls server
dev tun
persist-tun
persist-key
{% if ca %}
<ca>
{{ ca }}
</ca>
{% else %}ca /etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem{% endif %}
{% if key %}
<key>
{{ key }}
</key>
{% else %}key /etc/certidude/authority/{{ authority.namespace }}/host_key.pem{% endif %}
{% if cert %}
<cert>
{{ cert }}
</cert>
{% else %}cert /etc/certidude/authority/{{ authority.namespace }}/host_cert.pem{% endif %}

@@ -0,0 +1,20 @@
# Install packages on Ubuntu & Fedora
which apt && apt install openvpn
which dnf && dnf install openvpn
# Create OpenVPN configuration file
cat > /etc/openvpn/{{ session.authority.namespace }}.conf << EOF
{% include "snippets/openvpn-client.conf" %}
EOF
# Restart OpenVPN service
systemctl restart openvpn
{#
Some notes:
- Ubuntu 16.04 ships OpenVPN 2.3 which doesn't support AES-128-GCM
- NetworkManager's OpenVPN profile importer doesn't understand multiple remotes
- Tunnelblick and OpenVPN Connect apps don't have a method to update CRL
#}

@@ -0,0 +1,47 @@
# Generate keypair and submit CSR
{% if common_name %}$NAME = "{{ common_name }}"
{% else %}$NAME = $env:computername.toLower()
{% endif %}
@"
[NewRequest]
Subject = "CN=$NAME"
Exportable = FALSE
KeySpec = 1
KeyUsage = 0xA0
MachineKeySet = True
ProviderType = 12
RequestType = PKCS10
{% if authority.certificate.algorithm == "ec" %}ProviderName = "Microsoft Software Key Storage Provider"
KeyAlgorithm = ECDSA_P384
{% else %}ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
KeyLength = 2048
{% endif %}"@ | Out-File req.inf
C:\Windows\system32\certreq.exe -new -f -q req.inf host_csr.pem
Invoke-WebRequest `{% if token %}
-Uri 'https://{{ authority.namespace }}:8443/api/token/?token={{ token }}' `
-Method PUT `{% else %}
-Uri 'https://{{ authority.namespace }}:8443/api/request/?wait=yes&autosign=yes' `
-Method POST `{% endif %}
-TimeoutSec 900 `
-InFile host_csr.pem `
-ContentType application/pkcs10 `
-MaximumRedirection 3 -OutFile host_cert.pem
# Import certificate
Import-Certificate -FilePath host_cert.pem -CertStoreLocation Cert:\LocalMachine\My
{#
On Windows 7 the Import-Certificate cmdlet is missing,
but certutil.exe can be used instead:
C:\Windows\system32\certutil.exe -addstore My host_cert.pem
Everything seems to work except after importing the certificate
it is not properly associated with the private key,
that means "You have private key that corresponds to this certificate" is not
shown under "Valid from ... to ..." in MMC.
This results in error code 13806 during IKEv2 handshake and error message
"IKE failed to find valid machine certificate"
#}

@@ -0,0 +1,11 @@
# Use short hostname as common name
test -e /sbin/uci && NAME=$(uci get system.@system[0].hostname)
test -e /bin/hostname && NAME=$(hostname)
test -n "$NAME" || NAME=$(cat /proc/sys/kernel/hostname)
{% include "snippets/request-common.sh" %}
# Submit CSR and save signed certificate
curl --cert-status -f -L -H "Content-type: application/pkcs10" \
--data-binary @/etc/certidude/authority/{{ authority.namespace }}/host_req.pem \
-o /etc/certidude/authority/{{ authority.namespace }}/host_cert.pem \
'http://{{ authority.namespace }}/api/request/?wait=yes&autosign=yes'

@@ -0,0 +1,19 @@
# Create directories
mkdir -p /etc/certidude/authority/{{ authority.namespace }}
# Delete CA certificate if checksum doesn't match
echo {{ authority.certificate.md5sum }} /etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem | md5sum -c \
|| rm -fv /etc/certidude/authority/{{ authority.namespace }}/*.pem
{% include "snippets/store-authority.sh" %}
{% include "snippets/update-trust.sh" %}
# Generate private key
test -e /etc/certidude/authority/{{ authority.namespace }}/host_key.pem \
|| {% if authority.certificate.algorithm == "ec" %}openssl ecparam -name secp384r1 -genkey -noout \
-out /etc/certidude/authority/{{ authority.namespace }}/host_key.pem{% else %}openssl genrsa \
-out /etc/certidude/authority/{{ authority.namespace }}/host_key.pem 2048{% endif %}
test -e /etc/certidude/authority/{{ authority.namespace }}/host_req.pem \
|| openssl req -new -sha384 -subj "/CN=$NAME" \
-key /etc/certidude/authority/{{ authority.namespace }}/host_key.pem \
-out /etc/certidude/authority/{{ authority.namespace }}/host_req.pem
echo "If CSR submission fails, you can copy paste it to Certidude:"
cat /etc/certidude/authority/{{ authority.namespace }}/host_req.pem

@@ -0,0 +1,7 @@
# Use fully qualified name
test -e /sbin/uci && NAME=$(nslookup $(uci get network.wan.ipaddr) | grep "name =" | head -n1 | cut -d "=" -f 2 | xargs)
test -e /bin/hostname && NAME=$(hostname -f)
test -n "$NAME" || NAME=$(cat /proc/sys/kernel/hostname)
{% include "snippets/request-common.sh" %}
{% include "snippets/submit-request-wait.sh" %}

@@ -0,0 +1,11 @@
# See more on http://unmitigatedrisk.com/?p=241 why we're doing this
cat << EOF > /etc/systemd/system/nginx-ocsp-cache.service
{% include "snippets/nginx-ocsp-cache.service" %}EOF
cat << EOF > /etc/systemd/system/nginx-ocsp-cache.timer
{% include "snippets/nginx-ocsp-cache.timer" %}EOF
systemctl enable nginx-ocsp-cache.service
systemctl enable nginx-ocsp-cache.timer
systemctl start nginx-ocsp-cache.service
systemctl start nginx-ocsp-cache.timer

@@ -0,0 +1,5 @@
# Save CA certificate
mkdir -p /etc/certidude/authority/{{ authority.namespace }}/
test -e /etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem \
|| cat << EOF > /etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem
{{ authority.certificate.blob }}EOF

@@ -0,0 +1,28 @@
cat > /etc/ipsec.conf << EOF
config setup
strictcrlpolicy=yes
ca {{ authority.namespace }}
auto=add
cacert=/etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem
conn client-to-site
auto=start
right={{ authority.namespace }}
rightsubnet=0.0.0.0/0
rightca="{{ session.authority.certificate.distinguished_name }}"
left=%defaultroute
leftcert=/etc/certidude/authority/{{ authority.namespace }}/host_cert.pem
leftsourceip=%config
leftca="{{ session.authority.certificate.distinguished_name }}"
keyexchange=ikev2
keyingtries=%forever
dpdaction=restart
closeaction=restart
ike=aes256-sha384-{% if session.authority.certificate.algorithm == "ec" %}ecp384{% else %}modp2048{% endif %}!
esp=aes128gcm16-aes128gmac-{% if session.authority.certificate.algorithm == "ec" %}ecp384{% else %}modp2048{% endif %}!
EOF
echo ": {% if session.authority.certificate.algorithm == "ec" %}ECDSA{% else %}RSA{% endif %} {{ authority.namespace }}.pem" > /etc/ipsec.secrets
ipsec restart

@@ -0,0 +1,17 @@
# Install packages on Ubuntu & Fedora, patch Fedora paths
which apt && apt install strongswan
which dnf && dnf install strongswan
test -e /etc/strongswan && test -e /etc/ipsec.conf || ln -s strongswan/ipsec.conf /etc/ipsec.conf
test -e /etc/strongswan && test -e /etc/ipsec.d || ln -s strongswan/ipsec.d /etc/ipsec.d
test -e /etc/strongswan && test -e /etc/ipsec.secrets || ln -s strongswan/ipsec.secrets /etc/ipsec.secrets
# Set SELinux context
chcon --type=home_cert_t /etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem /etc/ipsec.d/cacerts/{{ authority.namespace }}.pem
chcon --type=home_cert_t /etc/certidude/authority/{{ authority.namespace }}/host_cert.pem /etc/ipsec.d/certs/{{ authority.namespace }}.pem
chcon --type=home_cert_t /etc/certidude/authority/{{ authority.namespace }}/host_key.pem /etc/ipsec.d/private/{{ authority.namespace }}.pem
# Patch AppArmor
cat << EOF > /etc/apparmor.d/local/usr.lib.ipsec.charon
/etc/certidude/authority/** r,
EOF
systemctl restart apparmor

@@ -0,0 +1,6 @@
# Submit CSR and save signed certificate
curl --cert-status -f -L -H "Content-type: application/pkcs10" \
--cacert /etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem \
--data-binary @/etc/certidude/authority/{{ authority.namespace }}/host_req.pem \
-o /etc/certidude/authority/{{ authority.namespace }}/host_cert.pem \
'https://{{ authority.namespace }}:8443/api/request/?wait=yes'

@@ -0,0 +1,4 @@
# Install CA certificate
@"
{{ authority.certificate.blob }}"@ | Out-File ca_cert.pem
Import-Certificate -FilePath ca_cert.pem -CertStoreLocation Cert:\LocalMachine\Root

@@ -0,0 +1,18 @@
# Insert into Fedora trust store. Applies to curl, Firefox, Chrome, Chromium
test -e /etc/pki/ca-trust/source/anchors \
&& ln -s /etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem /etc/pki/ca-trust/source/anchors/{{ authority.namespace }} \
&& update-ca-trust
# Insert into Ubuntu trust store, only applies to curl
test -e /usr/local/share/ca-certificates/ \
&& ln -f -s /etc/certidude/authority/{{ authority.namespace }}/ca_cert.pem /usr/local/share/ca-certificates/{{ authority.namespace }}.crt \
&& update-ca-certificates
# Patch Firefox trust store on Ubuntu
if [ -d /usr/lib/firefox ]; then
if [ ! -h /usr/lib/firefox/libnssckbi.so ]; then
apt install -y p11-kit p11-kit-modules
mv /usr/lib/firefox/libnssckbi.so /usr/lib/firefox/libnssckbi.so.bak
ln -s /usr/lib/x86_64-linux-gnu/pkcs11/p11-kit-trust.so /usr/lib/firefox/libnssckbi.so
fi
fi

@@ -0,0 +1,36 @@
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
{% include "snippets/update-trust.ps1" %}
{% include "snippets/request-client.ps1" %}
# Set up IPSec VPN tunnel to {{ authority.namespace }}
Remove-VpnConnection -AllUserConnection -Force "IPSec to {{ authority.namespace }}"
Add-VpnConnection `
-Name "IPSec to {{ authority.namespace }}" `
-ServerAddress {{ authority.namespace }} `
-AuthenticationMethod MachineCertificate `
-EncryptionLevel Maximum `
-SplitTunneling `
-TunnelType ikev2 `
-PassThru -AllUserConnection
# Harden VPN configuration
Set-VpnConnectionIPsecConfiguration `
-ConnectionName "IPSec to {{ authority.namespace }}" `
-AuthenticationTransformConstants GCMAES128 `
-CipherTransformConstants GCMAES128 `
-EncryptionMethod AES256 `
-IntegrityCheckMethod SHA384 `
-DHGroup {% if authority.certificate.algorithm == "ec" %}ECP384{% else %}Group14{% endif %} `
-PfsGroup {% if authority.certificate.algorithm == "ec" %}ECP384{% else %}PFS2048{% endif %} `
-PassThru -AllUserConnection -Force
{#
AuthenticationTransformConstants - ESP integrity algorithm, one of: None MD596 SHA196 SHA256128 GCMAES128 GCMAES192 GCMAES256
CipherTransformConstants - ESP symmetric cipher, one of: DES DES3 AES128 AES192 AES256 GCMAES128 GCMAES192 GCMAES256
EncryptionMethod - IKE symmetric cipher, one of: DES DES3 AES128 AES192 AES256
IntegrityCheckMethod - IKE hash algorithm, one of: MD5 SHA196 SHA256 SHA384
DHGroup = IKE key exchange, one of: None Group1 Group2 Group14 ECP256 ECP384 Group24
PfsGroup = ESP key exchange, one of: None PFS1 PFS2 PFS2048 ECP256 ECP384 PFSMM PFS24
#}