1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
# Copyright 2021-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
# Migrate rsa keys into PKI configuration
import base64
import os
import struct
from cryptography.hazmat.primitives.asymmetric import rsa
from vyos.configtree import ConfigTree
from vyos.pki import load_private_key
from vyos.pki import encode_public_key
from vyos.pki import encode_private_key
pki_base = ['pki']
ipsec_site_base = ['vpn', 'ipsec', 'site-to-site', 'peer']
rsa_keys_base = ['vpn', 'rsa-keys']
LOCAL_KEY_PATHS = ['/config/auth/', '/config/ipsec.d/rsa-keys/']
def migrate_from_vyatta_key(data):
data = base64.b64decode(data[2:])
length = struct.unpack('B', data[:1])[0]
e = int.from_bytes(data[1:1+length], 'big')
n = int.from_bytes(data[1+length:], 'big')
public_numbers = rsa.RSAPublicNumbers(e, n)
return public_numbers.public_key()
def wrapped_pem_to_config_value(pem):
return "".join(pem.strip().split("\n")[1:-1])
local_key_name = 'localhost'
def migrate(config: ConfigTree) -> None:
if config.exists(rsa_keys_base):
if not config.exists(pki_base + ['key-pair']):
config.set(pki_base + ['key-pair'])
config.set_tag(pki_base + ['key-pair'])
if config.exists(rsa_keys_base + ['local-key', 'file']):
local_file = config.return_value(rsa_keys_base + ['local-key', 'file'])
local_path = None
local_key = None
for path in LOCAL_KEY_PATHS:
full_path = os.path.join(path, local_file)
if os.path.exists(full_path):
local_path = full_path
break
if local_path:
with open(local_path, 'r') as f:
local_key_data = f.read()
local_key = load_private_key(local_key_data, wrap_tags=False)
if local_key:
local_key_pem = encode_private_key(local_key)
config.set(pki_base + ['key-pair', local_key_name, 'private', 'key'], value=wrapped_pem_to_config_value(local_key_pem))
else:
print('Failed to migrate local RSA key')
if config.exists(rsa_keys_base + ['rsa-key-name']):
for rsa_name in config.list_nodes(rsa_keys_base + ['rsa-key-name']):
if not config.exists(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key']):
continue
vyatta_key = config.return_value(rsa_keys_base + ['rsa-key-name', rsa_name, 'rsa-key'])
public_key = migrate_from_vyatta_key(vyatta_key)
if public_key:
public_key_pem = encode_public_key(public_key)
config.set(pki_base + ['key-pair', rsa_name, 'public', 'key'], value=wrapped_pem_to_config_value(public_key_pem))
else:
print(f'Failed to migrate rsa-key "{rsa_name}"')
config.delete(rsa_keys_base)
if config.exists(ipsec_site_base):
for peer in config.list_nodes(ipsec_site_base):
mode = config.return_value(ipsec_site_base + [peer, 'authentication', 'mode'])
if mode != 'rsa':
continue
config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'local-key'], value=local_key_name)
remote_key_name = config.return_value(ipsec_site_base + [peer, 'authentication', 'rsa-key-name'])
config.set(ipsec_site_base + [peer, 'authentication', 'rsa', 'remote-key'], value=remote_key_name)
config.delete(ipsec_site_base + [peer, 'authentication', 'rsa-key-name'])
|