From 6f66e71e4622c54058b8689d4be730905d69fe22 Mon Sep 17 00:00:00 2001
From: sarthurdev <965089+sarthurdev@users.noreply.github.com>
Date: Thu, 17 Jun 2021 18:08:58 +0200
Subject: pki: T3642: New PKI config and management
---
smoketest/scripts/cli/test_pki.py | 95 +++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
create mode 100755 smoketest/scripts/cli/test_pki.py
(limited to 'smoketest')
diff --git a/smoketest/scripts/cli/test_pki.py b/smoketest/scripts/cli/test_pki.py
new file mode 100755
index 000000000..60287a0b4
--- /dev/null
+++ b/smoketest/scripts/cli/test_pki.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+import unittest
+
+from base_vyostest_shim import VyOSUnitTestSHIM
+from vyos.configsession import ConfigSession
+from vyos.configsession import ConfigSessionError
+
+base_path = ['pki']
+
+valid_ca_cert = 'MIIDgTCCAmmgAwIBAgIUeM0mATGs+sKF7ViBM6DEf9fQ19swDQYJKoZIhvcNAQELBQAwVzELMAkGA1UEBhMCR0IxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAcMCVNvbWUtQ2l0eTENMAsGA1UECgwEVnlPUzEQMA4GA1UEAwwHVnlPUyBDQTAeFw0yMTA2MjgxMzE2NDZaFw0yNjA2MjcxMzE2NDZaMFcxCzAJBgNVBAYTAkdCMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQHDAlTb21lLUNpdHkxDTALBgNVBAoMBFZ5T1MxEDAOBgNVBAMMB1Z5T1MgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDK98WwZIqgC6teHPSsyKLLRtboy55aisJN0D3iHJ8WGKkDmIrdCR2LI4J5C82ErfPOzl4Ck4vTmqh8wnuK/dhUxxzNdFJBMPHAe/E+UawYrubtJj5g8iHYowZJT5HQKnZbcqlPvl6EizA+etO48WGljKhpimj9/LVTp81+BtFNP4tJ/vOl+iqyJ0+PxiqQNDJgAF18meQRKaT9CcXycsciG9snMlB1tdOR7KDbi8lJ86lOi5ukPJaiMgWEu4UlyFVyHJ/68NvtwRhYerMoQquqDs21OXkOd8spZL6qEsxMeK8InedA7abPaxgxORpHguPQV4Ib5HBH9Chdb9zBMheZAgMBAAGjRTBDMA8GA1UdEwEB/wQFMAMBAf8wIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAbwJZifMEDbrKPQfGLp7ZA1muM728o4EYmmE79eWwH22wGMSZI7T2xr5zRlFLs+Jha917yQK4b5xBMjQRAJlHKjzNLJ+3XaGlnWjaTBJ2SC5YktrmXRAIS7PxTRk/r1bHs/D00+sEWewbFYr8Js4a1Cv4TksTNyjHx8pvphA+KIx/4qdojTslz+oH/cakUz0M9fh2B2xsO4bab5vX+LGLCK7jjeAL4Zyjf1hDyx+Ri79L5N8h4Q69fER4cIkW7KVKUOyjEg3N4ST56urdycmyq9bXFz5pRxuZLInA6RRToJrL8i0aPLJ6SyMujfREfjqOxdW5vyNF5/RkY+5Nz8JMgQ=='
+valid_ca_private_key = 'MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDK98WwZIqgC6teHPSsyKLLRtboy55aisJN0D3iHJ8WGKkDmIrdCR2LI4J5C82ErfPOzl4Ck4vTmqh8wnuK/dhUxxzNdFJBMPHAe/E+UawYrubtJj5g8iHYowZJT5HQKnZbcqlPvl6EizA+etO48WGljKhpimj9/LVTp81+BtFNP4tJ/vOl+iqyJ0+PxiqQNDJgAF18meQRKaT9CcXycsciG9snMlB1tdOR7KDbi8lJ86lOi5ukPJaiMgWEu4UlyFVyHJ/68NvtwRhYerMoQquqDs21OXkOd8spZL6qEsxMeK8InedA7abPaxgxORpHguPQV4Ib5HBH9Chdb9zBMheZAgMBAAECggEAa/CK5L0DcAvkrd9OS9lDokFhJ1qqM1KZ9NHrJyW7gP/KWow0RUqEuKtAxuj8+jOcdn4PRuV6tiUIt5iiJQ/MjYF6ktTqrZq+5nPDnzXGBTZ2vuXYxKvgThqczD4RuJfsa8O1wR/nmit/k6q0kCVmnakJI1+laHWNZRjXUs+DXcWbrUN5D4/5kyjvFilH1c8arfrO2O4DcwfX1zNbxicgYrGmjE5m6WCZKWdcgpBcIQShZfNATfXIEZ16WmDIFZnuOEUtFAzweR2ataLQNoyaTUeEe6g+ZDtUQIGKR/f0+Z4T/JMJfPX/vRn0l3nRJWWC7Okpa2xb0hVdBmS/op+TNQKBgQDvNGAkS4uUx8xw724kzCKQJRnzR80AQ6b2FoqRbAevWm+i0ntsCMyvCItAQS8Bw+9fgITvsmd9SdYPncMQZ1oQYPk5yso/SPUyuNPXtygDxUP1xS1yja5MObqyrq2O2EzcxiVxEHGlZMLTNxNA1tE8nF4c0nQpV/EfLtkQFnnUSwKBgQDZOA2hiLaiDlPj03S4UXDu6aUD2o07782CUKl6A331ZhH/8zGEiUvBKg8IG/2FyCHQDC0C6rbfoarAhrRGbDHKkDTKNmThTj+IYBkLt/5OATvqkEw8eL0nB+PY5JKH04/jE0F/YM/StUsgxvMCVhtp0u/d2Hq4V9skxah6oFbtKwKBgGEvs3wroWtyffLIpMSYl9Ze7Js2aekYk4ZahDQvYzPwl3jc8b5kGN1oqEMT+MhL1j7EFb7ZikiSLkGsBGvuwd3zuG6toNxzhQP1qkRzqvNVO5ZoZV2siMt5jQw6AlQON7RfYSj92F6tgKaWMuFeJibtFSO6se12SIY134U0zIzfAoGAQWF7yNkrj4+cdICbKzdoNKEiyAwqYpYFV2oL+OvAJ/L3DAEZMHla0eNk7t3t6yyX8NUZXz1imeFBUf25mVDLk9rf6NWCe8ZfnR6/qyVQaA47CJkyOSlmVa8sR4ZVDIkDUCflmP98zkE/QbhgQJ3GVo3lIPMdzQq0rVbJJU/Jmk0CgYEAtHRNaoKBsxKfb7N7ewlaMzwcULIORODjWM8MUXM+R50F/2uYMiTvpz6eIUVfXoFyQoioYI8kcDZ8NamiQIS7uZsHfKpgMDJkV3kOoZQusoDhasGQ0SOnxbz/y0XmNUtAePipH0jPY1SYUvWbvm2ya4aWVhBFly9hi2ZeHiVxVhk='
+valid_cert = 'MIIB9zCCAZygAwIBAgIUQ5G1nyASL/YsKGyLNGhRPPQyo4kwCgYIKoZIzj0EAwIwXjELMAkGA1UEBhMCR0IxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAcMCVNvbWUtQ2l0eTENMAsGA1UECgwEVnlPUzEXMBUGA1UEAwwOVnlPUyBUZXN0IENlcnQwHhcNMjEwNjI4MTMyNjIyWhcNMjIwNjI4MTMyNjIyWjBeMQswCQYDVQQGEwJHQjETMBEGA1UECAwKU29tZS1TdGF0ZTESMBAGA1UEBwwJU29tZS1DaXR5MQ0wCwYDVQQKDARWeU9TMRcwFQYDVQQDDA5WeU9TIFRlc3QgQ2VydDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABBsebIt+8rr2UysTpL8NnYUtmt47e3sC3H9IO8iI/N4uFrmGVgTLE2G+RDGzZgG/r7LviJSTuE9HX7wHLcIr0SmjODA2MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwEwDgYDVR0PAQH/BAQDAgeAMAoGCCqGSM49BAMCA0kAMEYCIQD5xK5kdC3TJ7SZrBGvzIM7E7Cil/KZJUyQDR9eFNNZVQIhALg8DTfrwAawf8L+Ncjn/l2gd5cB0nGij0D7uYnm3zf/'
+valid_dh_params = 'MIIBCAKCAQEAnNldZCrJk5MxhFoUlvvaYmUO+TmtL0uL62H2RIHJ+O0R+8vzdGPh6zDAzo46EJK735haUgu8+A1RTsXDOXcwBqDlVe0hYj9KaPHz1HpfNKntpoPCJAYJwiH8dd5zVMH+iBwEKlrfteV9vWHn0HUxgLJFSLp5o6y0qpKPREJu6k0XguGScrPaIw6RUwsoDy3unHfk+YeC0o040R18F75V1mXWTjQlEgM7ZO2JZkLGkhW30jB0vSHrkrFqOvtPUiyG7r3+j18IUYLTN0s+5FOCfCjvSVKibNlB1vUz5y/9Ve8roctpkRM/5R5FA0mtbl7U/yMSX4FRIQ/A9BlHiu4bowIBAg=='
+valid_public_ec_key = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAoInInwjlu/3+wDqvRa/Eyg3EMvBpPyq2v4jqEtEh2n4lOCi7ZgNjr+1sQSvrn8mccpALYl3/RKOougC5oQzCg=='
+valid_private_rsa_key = 'MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDDoAVyJPpcLBFs2NdS1qMOSj7mwKBKVZiBN3nqbLiOvEHbVe22UMNvUFU3sGs2Ta2zXwhPF3d6vPPsGlYTkO3XAffMSNXhjCsvWHiIOR4JrWf598Bpt+txBsxsa12kM3/HM7RDf3zdN2gTtwzrcWzu+zOTXlqJ2OSq/BRRZO9IMbQLQ1/h42GJHEr4THnY4zDqUjmMmIuiBXn4xoE4KFLH1+xPTVleeKvPPeJ1wsshoUjlXYOgcsrXasDUt5gtkkXsVQwR9Lvbh+RcBhT+tJmrX9Cwq4YAd3tLSNJARS9HanRZ8uV0RTyZsImdw1Fr5ySpG2oEp/Z5mbL6QYqDmQ+DAgMBAAECggEAGu7qMQf0TEJo98J3CtmwQ2Rnep+ksfdM8uVvbJ4hXs1+h7Mx8jr2XVoDEZLBgA17z8lSvIjvkz92mdgaZ8E5bbPAqSiSAeapf3A/0AmFIDH2scyxehyvVrVn6blygAvzGLr+o5hm2ZIqSySVq8jHBbQiKrT/5CCvgvcH2Rj7dMXdT5lL73tCRJZsgvFNlxyj4Omj9Lh7SjL+tIwEQaLFbvANXrZ/BPyw4OlK8daBNg9b5GvJSDitAVMgDEEApGYu1iNwMM4UJSQAC27eJdr+qJO6DDqktWOyWcyXrxJ9mDVKFNbb9QNQZDj7bFfm6rCuSdH9yYe3vly+SNJqtyCiwQKBgQDvemt/57KiwQffmoKR65NAZsQvmA4PtELYOV8NPeYH1BZN/EPmCc74iELJdQPFDYy903aRJEPGt7jfqprdPexLwt73P/XiUjPrsbqgJqfF/EMiczxAktyW3xBt2lIWU1MUUmO1ps+ZZEg8Ks4eK/3+FWqbwZ8drDBUT9BthUA0oQKBgQDRHxU6bu938PGweFJcIG6U21nsYaWiwCiTLXA5vWZ+UEqz81BUye6tIcCDgeku3HvC/0ycvrBM9F4AZCjnnEvrAJHKl6e4j+C4IpghGQvRvQ9ihDs9JIHnaoUC1i8dE3ISbbp1r7CN+J/HnAC2OeECMJuffXdnkVWaxRdxU+9towKBgCwFVeNyJO00DI126o+GPVA2U9Pn4JXUbgEvMqDNgw5nVx5Iw/ZyUSBwc85yexnq7rcqOv5dKzRJK2u6AbOvoVMf5DqRAFL1B2RJDGRKFscXIwQfKLE6DeCR6oQ3AKXn9TqkFn4axsiMnZapy6/SKGNfbnRpOCWNNGkbLtYjC3VhAoGAN0kOZapaaM0sOEk3DOAOHBB5j4KpNYOztmU23Cz0YcR8W2KiBCh2jxLzQFEiAp+LoJu59156YX3hNB1GqySo9XHrGTJKxwJSmJucuHNUqphe7t6igqGaLkH89CkHv5oaeEDGIMLX3FC0fSMDFSnsEJYlLl8PKDRF+2rLrcxQ6h0CgYAZllNu8a7tE6cM6QsCILQnNjuLuZRX8/KYWRqBJxatwZXCcMe2jti1HKTVVVCyYffOFa1QcAjCPknAmAz80l3eg6a75NnEXo0J6YLAOOxd8fD2/HidhbceCmTF+3msidIzCsBidBkgn6V5TXx2IyMSxGsJxVHfSKeooUQn6q76sg=='
+
+class TestPKI(VyOSUnitTestSHIM.TestCase):
+ def setUp(self):
+ self.cli_delete(base_path)
+
+ def tearDown(self):
+ self.cli_delete(base_path)
+ self.cli_commit()
+
+ def test_valid_pki(self):
+ # Valid CA
+ self.cli_set(base_path + ['ca', 'smoketest', 'certificate', valid_ca_cert])
+ self.cli_set(base_path + ['ca', 'smoketest', 'private', 'key', valid_ca_private_key])
+ self.cli_set(base_path + ['ca', 'smoketest', 'private', 'type', 'rsa'])
+
+ # Valid cert
+ self.cli_set(base_path + ['certificate', 'smoketest', 'certificate', valid_cert])
+
+ # Valid DH
+ self.cli_set(base_path + ['dh', 'smoketest', 'parameters', valid_dh_params])
+
+ # Valid public key
+ self.cli_set(base_path + ['key-pair', 'smoketest', 'public', 'key', valid_public_ec_key])
+ self.cli_set(base_path + ['key-pair', 'smoketest', 'type', 'ec'])
+
+ # Valid private key
+ self.cli_set(base_path + ['key-pair', 'smoketest1', 'private', 'key', valid_private_rsa_key])
+ self.cli_set(base_path + ['key-pair', 'smoketest1', 'type', 'rsa'])
+
+ self.cli_commit()
+
+ def test_invalid_ca_valid_certificate(self):
+ self.cli_set(base_path + ['ca', 'smoketest', 'certificate', valid_cert])
+
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ def test_invalid_certificate(self):
+ self.cli_set(base_path + ['certificate', 'smoketest', 'certificate', 'invalidcertdata'])
+
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ def test_invalid_public_key(self):
+ self.cli_set(base_path + ['key-pair', 'smoketest', 'public', 'key', 'invalidkeydata'])
+ self.cli_set(base_path + ['key-pair', 'smoketest', 'type', 'rsa'])
+
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ def test_invalid_private_key(self):
+ self.cli_set(base_path + ['key-pair', 'smoketest', 'private', 'key', 'invalidkeydata'])
+ self.cli_set(base_path + ['key-pair', 'smoketest', 'type', 'rsa'])
+
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ def test_invalid_dh_parameters(self):
+ self.cli_set(base_path + ['dh', 'smoketest', 'parameters', 'thisisinvalid'])
+
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
--
cgit v1.2.3
From f5a8a9cdfe52c331177c8bc7b8fb84fc08d4f60a Mon Sep 17 00:00:00 2001
From: sarthurdev <965089+sarthurdev@users.noreply.github.com>
Date: Tue, 29 Jun 2021 11:06:44 +0200
Subject: pki: ipsec: T3642: Migrate IPSec to use PKI configuration
---
data/templates/ipsec/swanctl.conf.tmpl | 6 +-
data/templates/ipsec/swanctl/peer.tmpl | 2 +-
.../include/pki/certificate-key.xml.i | 15 +--
.../include/pki/dh-parameters.xml.i | 14 ---
.../include/pki/openvpn_tls-auth.xml.i | 14 ---
interface-definitions/pki.xml.in | 8 +-
interface-definitions/vpn_ipsec.xml.in | 38 +-----
op-mode-definitions/pki.xml.in | 6 +-
smoketest/configs/pki-ipsec | 95 ++++++++++++++
src/conf_mode/vpn_ipsec.py | 89 ++++++++-----
src/migration-scripts/ipsec/6-to-7 | 137 +++++++++++++++++++++
src/op_mode/pki.py | 4 +-
12 files changed, 310 insertions(+), 118 deletions(-)
delete mode 100644 interface-definitions/include/pki/dh-parameters.xml.i
delete mode 100644 interface-definitions/include/pki/openvpn_tls-auth.xml.i
create mode 100644 smoketest/configs/pki-ipsec
create mode 100755 src/migration-scripts/ipsec/6-to-7
(limited to 'smoketest')
diff --git a/data/templates/ipsec/swanctl.conf.tmpl b/data/templates/ipsec/swanctl.conf.tmpl
index ea6d85743..9e629b176 100644
--- a/data/templates/ipsec/swanctl.conf.tmpl
+++ b/data/templates/ipsec/swanctl.conf.tmpl
@@ -55,9 +55,9 @@ secrets {
}
{% elif peer_conf.authentication.mode == 'x509' %}
private_{{ peer_conn_name }} {
- file = {{ peer_conf.authentication.x509.key.file }}
-{% if "password" in peer_conf.authentication.x509.key and peer_conf.authentication.x509.key.password %}
- secret = "{{ peer_conf.authentication.x509.key.password}}"
+ file = {{ peer_conf.authentication.x509.certificate }}.pem
+{% if peer_conf.authentication.x509.passphrase is defined %}
+ secret = "{{ peer_conf.authentication.x509.passphrase }}"
{% endif %}
}
{% elif peer_conf.authentication.mode == 'rsa' and not ns.local_key_set %}
diff --git a/data/templates/ipsec/swanctl/peer.tmpl b/data/templates/ipsec/swanctl/peer.tmpl
index 0d01cd546..36cb1abfb 100644
--- a/data/templates/ipsec/swanctl/peer.tmpl
+++ b/data/templates/ipsec/swanctl/peer.tmpl
@@ -35,7 +35,7 @@
auth = {{ auth_type }}
{% endif %}
{% if peer_conf.authentication.mode == 'x509' %}
- certs = {{ peer_conf.authentication.x509.cert_file }}
+ certs = {{ peer_conf.authentication.x509.certificate }}.pem
{% elif peer_conf.authentication.mode == 'rsa' %}
pubkeys = localhost.pub
{% endif %}
diff --git a/interface-definitions/include/pki/certificate-key.xml.i b/interface-definitions/include/pki/certificate-key.xml.i
index b68f38442..7f26d25c1 100644
--- a/interface-definitions/include/pki/certificate-key.xml.i
+++ b/interface-definitions/include/pki/certificate-key.xml.i
@@ -1,17 +1,6 @@
-
-
- Certificate and private key in PKI configuration
-
- cert name
- Name of certificate in PKI configuration
-
-
- pki certificate
-
-
-
-
+#include
+
Private key passphrase
diff --git a/interface-definitions/include/pki/dh-parameters.xml.i b/interface-definitions/include/pki/dh-parameters.xml.i
deleted file mode 100644
index 6e69528e7..000000000
--- a/interface-definitions/include/pki/dh-parameters.xml.i
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- Diffie-Hellman parameters in PKI configuration
-
- DH name
- Name of DH params in PKI configuration
-
-
- pki dh
-
-
-
-
diff --git a/interface-definitions/include/pki/openvpn_tls-auth.xml.i b/interface-definitions/include/pki/openvpn_tls-auth.xml.i
deleted file mode 100644
index 2b9a69653..000000000
--- a/interface-definitions/include/pki/openvpn_tls-auth.xml.i
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- Static key for tls-auth in PKI configuration
-
- key name
- Name of static key in PKI configuration
-
-
- pki openvpn tls-auth
-
-
-
-
diff --git a/interface-definitions/pki.xml.in b/interface-definitions/pki.xml.in
index e818ae438..4b082cbc4 100644
--- a/interface-definitions/pki.xml.in
+++ b/interface-definitions/pki.xml.in
@@ -141,19 +141,19 @@
OpenVPN keys
-
+
- OpenVPN TLS auth key
+ OpenVPN shared secret key
- OpenVPN TLS auth key data
+ OpenVPN shared secret key data
- OpenVPN TLS auth key version
+ OpenVPN shared secret key version
diff --git a/interface-definitions/vpn_ipsec.xml.in b/interface-definitions/vpn_ipsec.xml.in
index 2031217ba..7b1b3a595 100644
--- a/interface-definitions/vpn_ipsec.xml.in
+++ b/interface-definitions/vpn_ipsec.xml.in
@@ -804,42 +804,8 @@
X.509 certificate
- #include
- #include
-
-
- File containing the X.509 Certificate Revocation List (CRL)
-
- txt
- File in /config/auth
-
-
-
-
-
- Key file and password to open it
-
-
-
-
- File containing the private key for the X.509 certificate for this host
-
- txt
- File in /config/auth
-
-
-
-
-
- Password that protects the private key
-
- txt
- Password that protects the private key
-
-
-
-
-
+ #include
+ #include
diff --git a/op-mode-definitions/pki.xml.in b/op-mode-definitions/pki.xml.in
index 0cea3db08..06b15eed4 100644
--- a/op-mode-definitions/pki.xml.in
+++ b/op-mode-definitions/pki.xml.in
@@ -134,14 +134,14 @@
Generate OpenVPN keys
-
+
- Generate OpenVPN TLS key
+ Generate OpenVPN shared secret key
- Commands for installing generated OpenVPN TLS key into running configuration
+ Commands for installing generated OpenVPN shared secret key into running configuration
<key name>
diff --git a/smoketest/configs/pki-ipsec b/smoketest/configs/pki-ipsec
new file mode 100644
index 000000000..7708a3cdd
--- /dev/null
+++ b/smoketest/configs/pki-ipsec
@@ -0,0 +1,95 @@
+interfaces {
+ dummy dum0 {
+ address 172.20.0.1/30
+ }
+ ethernet eth0 {
+ address 192.168.150.1/24
+ }
+}
+system {
+ config-management {
+ commit-revisions 100
+ }
+ console {
+ device ttyS0 {
+ speed 115200
+ }
+ }
+ host-name vyos
+ login {
+ user vyos {
+ authentication {
+ encrypted-password $6$2Ta6TWHd/U$NmrX0x9kexCimeOcYK1MfhMpITF9ELxHcaBU/znBq.X2ukQOj61fVI2UYP/xBzP4QtiTcdkgs7WOQMHWsRymO/
+ plaintext-password ""
+ }
+ }
+ }
+ ntp {
+ server time1.vyos.net {
+ }
+ server time2.vyos.net {
+ }
+ server time3.vyos.net {
+ }
+ }
+ syslog {
+ global {
+ facility all {
+ level info
+ }
+ facility protocols {
+ level debug
+ }
+ }
+ }
+}
+vpn {
+ ipsec {
+ esp-group MyESPGroup {
+ proposal 1 {
+ encryption aes128
+ hash sha1
+ }
+ }
+ ike-group MyIKEGroup {
+ proposal 1 {
+ dh-group 2
+ encryption aes128
+ hash sha1
+ }
+ }
+ ipsec-interfaces {
+ interface eth0
+ }
+ site-to-site {
+ peer 192.168.150.2 {
+ authentication {
+ mode x509
+ x509 {
+ ca-cert-file ovpn_test_ca.pem
+ cert-file ovpn_test_server.pem
+ key {
+ file ovpn_test_server.key
+ }
+ }
+ }
+ default-esp-group MyESPGroup
+ ike-group MyIKEGroup
+ local-address 192.168.150.1
+ tunnel 0 {
+ local {
+ prefix 172.20.0.0/24
+ }
+ remote {
+ prefix 172.21.0.0/24
+ }
+ }
+ }
+ }
+ }
+}
+
+
+// Warning: Do not remove the following line.
+// vyos-config-version: "bgp@1:broadcast-relay@1:cluster@1:config-management@1:conntrack@2:conntrack-sync@2:dhcp-relay@2:dhcp-server@5:dhcpv6-server@1:dns-forwarding@3:firewall@5:https@2:interfaces@22:ipoe-server@1:ipsec@6:isis@1:l2tp@3:lldp@1:mdns@1:nat@5:nat66@1:ntp@1:policy@1:pppoe-server@5:pptp@2:qos@1:quagga@9:rpki@1:salt@1:snmp@2:ssh@2:sstp@3:system@21:vrf@2:vrrp@2:vyos-accel-ppp@2:wanloadbalance@3:webproxy@2:zone-policy@1"
+// Release version: 1.4-rolling-202106290839
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index d598ff6da..e8e8b453a 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -23,6 +23,10 @@ from vyos.config import Config
from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_interface_exists
from vyos.ifconfig import Interface
+from vyos.pki import wrap_certificate
+from vyos.pki import wrap_crl
+from vyos.pki import wrap_public_key
+from vyos.pki import wrap_private_key
from vyos.template import ip_from_cidr
from vyos.template import render
from vyos.validate import is_ipv6_link_local
@@ -115,6 +119,8 @@ def get_config(config=None):
ipsec['interface_change'] = leaf_node_changed(conf, base + ['ipsec-interfaces', 'interface'])
ipsec['l2tp_exists'] = conf.exists(['vpn', 'l2tp', 'remote-access', 'ipsec-settings'])
ipsec['nhrp_exists'] = conf.exists(['protocols', 'nhrp', 'tunnel'])
+ ipsec['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),
+ get_first_key=True, no_tag_node_value_mangle=True)
ipsec['rsa_keys'] = conf.get_config_dict(['vpn', 'rsa-keys'], key_mangling=('-', '_'),
get_first_key=True, no_tag_node_value_mangle=True)
@@ -187,6 +193,24 @@ def get_dhcp_address(iface):
return ip_from_cidr(address)
return None
+def verify_pki(pki, x509_conf):
+ if not pki or 'ca' not in pki or 'certificate' not in pki:
+ raise ConfigError(f'PKI is not configured')
+
+ ca_cert_name = x509_conf['ca_certificate']
+ cert_name = x509_conf['certificate']
+
+ if not dict_search(f'ca.{ca_cert_name}.certificate', ipsec['pki']):
+ raise ConfigError(f'Missing CA certificate on specified PKI CA certificate "{ca_cert_name}"')
+
+ if not dict_search(f'certificate.{cert_name}.certificate', ipsec['pki']):
+ raise ConfigError(f'Missing certificate on specified PKI certificate "{cert_name}"')
+
+ if not dict_search(f'certificate.{cert_name}.private.key', ipsec['pki']):
+ raise ConfigError(f'Missing private key on specified PKI certificate "{cert_name}"')
+
+ return True
+
def verify(ipsec):
if not ipsec:
return None
@@ -237,24 +261,12 @@ def verify(ipsec):
if 'x509' not in peer_conf['authentication']:
raise ConfigError(f"Missing x509 settings on site-to-site peer {peer}")
- if 'key' not in peer_conf['authentication']['x509']:
- raise ConfigError(f"Missing x509 key on site-to-site peer {peer}")
-
- if 'ca_cert_file' not in peer_conf['authentication']['x509'] or 'cert_file' not in peer_conf['authentication']['x509']:
- raise ConfigError(f"Missing x509 settings on site-to-site peer {peer}")
+ x509 = peer_conf['authentication']['x509']
- if 'file' not in peer_conf['authentication']['x509']['key']:
- raise ConfigError(f"Missing x509 key file on site-to-site peer {peer}")
+ if 'ca_certificate' not in x509 or 'certificate' not in x509:
+ raise ConfigError(f"Missing x509 certificates on site-to-site peer {peer}")
- for key in ['ca_cert_file', 'cert_file', 'crl_file']:
- if key in peer_conf['authentication']['x509']:
- path = os.path.join(X509_PATH, peer_conf['authentication']['x509'][key])
- if not os.path.exists(path):
- raise ConfigError(f"File not found for {key} on site-to-site peer {peer}")
-
- key_path = os.path.join(X509_PATH, peer_conf['authentication']['x509']['key']['file'])
- if not os.path.exists(key_path):
- raise ConfigError(f"Private key not found on site-to-site peer {peer}")
+ verify_pki(ipsec['pki'], x509)
if peer_conf['authentication']['mode'] == 'rsa':
if not verify_rsa_local_key(ipsec):
@@ -320,6 +332,31 @@ def verify(ipsec):
if ('local' in tunnel_conf and 'prefix' in tunnel_conf['local']) or ('remote' in tunnel_conf and 'prefix' in tunnel_conf['remote']):
raise ConfigError(f"Local/remote prefix cannot be used with ESP transport mode on tunnel {tunnel} for site-to-site peer {peer}")
+def generate_pki_files(pki, x509_conf):
+ ca_cert_name = x509_conf['ca_certificate']
+ ca_cert_data = dict_search(f'ca.{ca_cert_name}.certificate', pki)
+ ca_cert_crls = dict_search(f'ca.{ca_cert_name}.crl', pki) or []
+ crl_index = 1
+
+ cert_name = x509_conf['certificate']
+ cert_data = dict_search(f'certificate.{cert_name}.certificate', pki)
+ key_data = dict_search(f'certificate.{cert_name}.private.key', pki)
+ protected = 'passphrase' in x509_conf
+
+ with open(os.path.join(CA_PATH, f'{ca_cert_name}.pem'), 'w') as f:
+ f.write(wrap_certificate(ca_cert_data))
+
+ for crl in ca_cert_crls:
+ with open(os.path.join(CRL_PATH, f'{ca_cert_name}_{crl_index}.pem'), 'w') as f:
+ f.write(wrap_crl(crl))
+ crl_index += 1
+
+ with open(os.path.join(CERT_PATH, f'{cert_name}.pem'), 'w') as f:
+ f.write(wrap_certificate(cert_data))
+
+ with open(os.path.join(KEY_PATH, f'{cert_name}.pem'), 'w') as f:
+ f.write(wrap_private_key(key_data, protected))
+
def generate(ipsec):
data = {}
@@ -334,24 +371,20 @@ def generate(ipsec):
data['marks'] = {}
data['rsa_local_key'] = verify_rsa_local_key(ipsec)
+ for path in [swanctl_dir, CERT_PATH, CA_PATH, CRL_PATH]:
+ if not os.path.exists(path):
+ os.mkdir(path, mode=0o755)
+
+ if not os.path.exists(KEY_PATH):
+ os.mkdir(KEY_PATH, mode=0o700)
+
if 'site_to_site' in data and 'peer' in data['site_to_site']:
for peer, peer_conf in ipsec['site_to_site']['peer'].items():
if peer in ipsec['dhcp_no_address']:
continue
if peer_conf['authentication']['mode'] == 'x509':
- cert_file = os.path.join(X509_PATH, peer_conf['authentication']['x509']['cert_file'])
- copy_file(cert_file, CERT_PATH, True)
-
- key_file = os.path.join(X509_PATH, peer_conf['authentication']['x509']['key']['file'])
- copy_file(key_file, X509_PATH, True)
-
- ca_cert_file = os.path.join(X509_PATH, peer_conf['authentication']['x509']['ca_cert_file'])
- copy_file(ca_cert_file, CA_PATH, True)
-
- if 'crl_file' in peer_conf['authentication']['x509']:
- crl_file = os.path.join(X509_PATH, peer_conf['authentication']['x509']['crl_file'])
- copy_file(crl_file, CRL_PATH, True)
+ generate_pki_files(ipsec['pki'], peer_conf['authentication']['x509'])
local_ip = ''
if 'local_address' in peer_conf:
diff --git a/src/migration-scripts/ipsec/6-to-7 b/src/migration-scripts/ipsec/6-to-7
new file mode 100755
index 000000000..6655fba93
--- /dev/null
+++ b/src/migration-scripts/ipsec/6-to-7
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# Migrate /config/auth certificates and keys into PKI configuration
+
+import os
+
+from sys import argv
+from sys import exit
+
+from vyos.configtree import ConfigTree
+from vyos.pki import load_certificate
+from vyos.pki import load_crl
+from vyos.pki import load_private_key
+from vyos.pki import encode_certificate
+from vyos.pki import encode_private_key
+
+if (len(argv) < 1):
+ print("Must specify file name!")
+ exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+pki_base = ['pki']
+ipsec_site_base = ['vpn', 'ipsec', 'site-to-site', 'peer']
+
+config = ConfigTree(config_file)
+changes_made = False
+
+AUTH_DIR = '/config/auth'
+
+def wrapped_pem_to_config_value(pem):
+ return "".join(pem.strip().split("\n")[1:-1])
+
+if config.exists(ipsec_site_base):
+ config.set(pki_base + ['ca'])
+ config.set_tag(pki_base + ['ca'])
+
+ config.set(pki_base + ['certificate'])
+ config.set_tag(pki_base + ['certificate'])
+
+ for peer in config.list_nodes(ipsec_site_base):
+ if not config.exists(ipsec_site_base + [peer, 'authentication', 'x509']):
+ continue
+
+ changes_made = True
+
+ peer_x509_base = ipsec_site_base + [peer, 'authentication', 'x509']
+ pki_name = 'peer_' + peer.replace(".", "-")
+
+ if config.exists(peer_x509_base + ['cert-file']):
+ cert_file = config.return_value(peer_x509_base + ['cert-file'])
+ cert_path = os.path.join(AUTH_DIR, cert_file)
+ cert = None
+
+ with open(cert_path, 'r') as f:
+ cert_data = f.read()
+ cert = load_certificate(cert_data, wrap_tags=False)
+
+ cert_pem = encode_certificate(cert)
+ config.set(pki_base + ['certificate', pki_name, 'certificate'], value=wrapped_pem_to_config_value(cert_pem))
+ config.set(peer_x509_base + ['certificate'], value=pki_name)
+ config.delete(peer_x509_base + ['cert-file'])
+
+ if config.exists(peer_x509_base + ['ca-cert-file']):
+ ca_cert_file = config.return_value(peer_x509_base + ['ca-cert-file'])
+ ca_cert_path = os.path.join(AUTH_DIR, ca_cert_file)
+ ca_cert = None
+
+ with open(ca_cert_path, 'r') as f:
+ ca_cert_data = f.read()
+ ca_cert = load_certificate(ca_cert_data, wrap_tags=False)
+
+ ca_cert_pem = encode_certificate(ca_cert)
+ config.set(pki_base + ['ca', pki_name, 'certificate'], value=wrapped_pem_to_config_value(ca_cert_pem))
+ config.set(peer_x509_base + ['ca-certificate'], value=pki_name)
+ config.delete(peer_x509_base + ['ca-cert-file'])
+
+ if config.exists(peer_x509_base + ['crl-file']):
+ crl_file = config.return_value(peer_x509_base + ['crl-file'])
+ crl_path = os.path.join(AUTH_DIR, crl_file)
+ crl = None
+
+ with open(crl_path, 'r') as f:
+ crl_data = f.read()
+ crl = load_crl(crl_data, wrap_tags=False)
+
+ crl_pem = encode_certificate(crl)
+ config.set(pki_base + ['ca', pki_name, 'crl'], value=wrapped_pem_to_config_value(crl_pem))
+ config.delete(peer_x509_base + ['crl-file'])
+
+ if config.exists(peer_x509_base + ['key', 'file']):
+ key_file = config.return_value(peer_x509_base + ['key', 'file'])
+ key_passphrase = None
+
+ if config.exists(peer_x509_base + ['key', 'password']):
+ key_passphrase = config.return_value(peer_x509_base + ['key', 'password'])
+
+ key_path = os.path.join(AUTH_DIR, key_file)
+ key = None
+
+ with open(key_path, 'r') as f:
+ key_data = f.read()
+ key = load_private_key(key_data, passphrase=key_passphrase, wrap_tags=False)
+
+ key_pem = encode_private_key(key, passphrase=key_passphrase)
+ config.set(pki_base + ['certificate', pki_name, 'private', 'key'], value=wrapped_pem_to_config_value(key_pem))
+
+ if key_passphrase:
+ config.set(pki_base + ['certificate', pki_name, 'private', 'password-protected'])
+ config.set(peer_x509_base + ['private-key-passphrase'], value=key_passphrase)
+
+ config.delete(peer_x509_base + ['key'])
+
+if changes_made:
+ try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+ except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ sys.exit(1)
diff --git a/src/op_mode/pki.py b/src/op_mode/pki.py
index 321a5e60d..d99a432aa 100755
--- a/src/op_mode/pki.py
+++ b/src/op_mode/pki.py
@@ -473,8 +473,8 @@ def generate_openvpn_key(name, install=False):
key_version = version_search[1]
print("Configure mode commands to install OpenVPN key:")
- print("set pki openvpn tls-auth %s key '%s'" % (name, key_data))
- print("set pki openvpn tls-auth %s version '%s'" % (name, key_version))
+ print("set pki openvpn shared-secret %s key '%s'" % (name, key_data))
+ print("set pki openvpn shared-secret %s version '%s'" % (name, key_version))
def generate_wireguard_key(name, install=False):
private_key = cmd('wg genkey')
--
cgit v1.2.3