wip
This commit is contained in:
parent
8b296ba6db
commit
cadb32cffd
1 changed files with 69 additions and 49 deletions
118
bin/dnssec
118
bin/dnssec
|
@ -8,12 +8,13 @@ from cryptography.utils import int_to_bytes
|
||||||
from cryptography.hazmat.primitives import serialization as crypto_serialization
|
from cryptography.hazmat.primitives import serialization as crypto_serialization
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
from hashlib import sha1, sha256
|
from hashlib import sha1, sha256
|
||||||
|
from json import dumps
|
||||||
|
|
||||||
|
|
||||||
def long_to_base64(n):
|
def long_to_base64(n):
|
||||||
return urlsafe_b64encode(int_to_bytes(n, None)).decode()
|
return urlsafe_b64encode(int_to_bytes(n, None)).decode()
|
||||||
|
|
||||||
domain = argv[1]
|
zone = argv[1]
|
||||||
repo = Repository(dirname(dirname(realpath(__file__))))
|
repo = Repository(dirname(dirname(realpath(__file__))))
|
||||||
#repo = Repository('.')
|
#repo = Repository('.')
|
||||||
|
|
||||||
|
@ -22,63 +23,63 @@ protocol = 3
|
||||||
algorithm = 8
|
algorithm = 8
|
||||||
algorithm_name = 'RSASHA256'
|
algorithm_name = 'RSASHA256'
|
||||||
|
|
||||||
# Private Key
|
def generate_signing_key_pair(zone, salt=''):
|
||||||
|
priv = repo.libs.rsa.generate_deterministic_rsa_private_key(
|
||||||
|
b64decode(str(repo.vault.random_bytes_as_base64_for(f'dnssec {salt} ' + zone)))
|
||||||
|
)
|
||||||
|
|
||||||
priv = repo.libs.rsa.generate_deterministic_rsa_private_key(
|
# https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/#cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers
|
||||||
b64decode(str(repo.vault.random_bytes_as_base64_for('dnssec' + domain)))
|
# https://crypto.stackexchange.com/a/21104
|
||||||
)
|
public_exponent = priv.private_numbers().public_numbers.e
|
||||||
|
modulo = priv.private_numbers().public_numbers.n
|
||||||
|
private_exponent = priv.private_numbers().d
|
||||||
|
prime1 = priv.private_numbers().p
|
||||||
|
prime2 = priv.private_numbers().q
|
||||||
|
exponent1 = priv.private_numbers().dmp1
|
||||||
|
exponent2 = priv.private_numbers().dmq1
|
||||||
|
coefficient = priv.private_numbers().iqmp
|
||||||
|
|
||||||
# https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/#cryptography.hazmat.primitives.asymmetric.rsa.RSAPrivateNumbers
|
dnskey = ''.join(priv.public_key().public_bytes(
|
||||||
# https://crypto.stackexchange.com/a/21104
|
crypto_serialization.Encoding.PEM,
|
||||||
public_exponent = priv.private_numbers().public_numbers.e
|
crypto_serialization.PublicFormat.SubjectPublicKeyInfo
|
||||||
modulo = priv.private_numbers().public_numbers.n
|
).decode().split('\n')[1:-2])
|
||||||
private_exponent = priv.private_numbers().d
|
|
||||||
prime1 = priv.private_numbers().p
|
return {
|
||||||
prime2 = priv.private_numbers().q
|
'dnskey': dnskey,
|
||||||
exponent1 = priv.private_numbers().dmp1
|
'dnskey_record': f'{zone}. IN DNSKEY {flags} {protocol} {algorithm} {dnskey}',
|
||||||
exponent2 = priv.private_numbers().dmq1
|
'privkey': {
|
||||||
coefficient = priv.private_numbers().iqmp
|
'Private-key-format': 'v1.3',
|
||||||
|
'Algorithm': f'{algorithm} ({algorithm_name})',
|
||||||
|
'Modulus': long_to_base64(modulo),
|
||||||
|
'PublicExponent': long_to_base64(public_exponent),
|
||||||
|
'PrivateExponent': long_to_base64(private_exponent),
|
||||||
|
'Prime1': long_to_base64(prime1),
|
||||||
|
'Prime2': long_to_base64(prime2),
|
||||||
|
'Exponent1': long_to_base64(exponent1),
|
||||||
|
'Exponent2': long_to_base64(exponent2),
|
||||||
|
'Coefficient': long_to_base64(coefficient),
|
||||||
|
'Created': 20230428110109,
|
||||||
|
'Publish': 20230428110109,
|
||||||
|
'Activate': 20230428110109,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# ZSK
|
||||||
|
|
||||||
print(f"""
|
|
||||||
Private-key-format: v1.3
|
|
||||||
Algorithm: {algorithm} ({algorithm_name})
|
|
||||||
Modulus: {long_to_base64(modulo)}
|
|
||||||
PublicExponent: {long_to_base64(public_exponent)}
|
|
||||||
PrivateExponent: {long_to_base64(private_exponent)}
|
|
||||||
Prime1: {long_to_base64(prime1)}
|
|
||||||
Prime2: {long_to_base64(prime2)}
|
|
||||||
Exponent1: {long_to_base64(exponent1)}
|
|
||||||
Exponent2: {long_to_base64(exponent2)}
|
|
||||||
Coefficient: {long_to_base64(coefficient)}
|
|
||||||
Created: 20230428110109
|
|
||||||
Publish: 20230428110109
|
|
||||||
Activate: 20230428110109
|
|
||||||
""")
|
|
||||||
|
|
||||||
# DNSKEY
|
# DNSKEY
|
||||||
|
|
||||||
pub = priv.public_key()
|
|
||||||
|
|
||||||
dnskey = ''.join(pub.public_bytes(
|
|
||||||
crypto_serialization.Encoding.PEM,
|
|
||||||
crypto_serialization.PublicFormat.SubjectPublicKeyInfo
|
|
||||||
).decode().split('\n')[1:-2])
|
|
||||||
|
|
||||||
value = f"{flags} {protocol} {algorithm} {dnskey}"
|
|
||||||
print(f"""
|
|
||||||
{domain}. IN DNSKEY {value}
|
|
||||||
""")
|
|
||||||
|
|
||||||
# DS
|
# DS
|
||||||
# https://gist.github.com/wido/4c6288b2f5ba6d16fce37dca3fc2cb4a#file-dnskey_to_dsrecord-py-L40
|
# https://gist.github.com/wido/4c6288b2f5ba6d16fce37dca3fc2cb4a#file-dnskey_to_dsrecord-py-L40
|
||||||
|
|
||||||
|
def _calc_ds(zone, flags, protocol, algorithm, dnskey):
|
||||||
def _calc_ds(domain, flags, protocol, algorithm, dnskey):
|
if zone.endswith('.') is False:
|
||||||
if domain.endswith('.') is False:
|
zone += '.'
|
||||||
domain += '.'
|
|
||||||
|
|
||||||
signature = bytes()
|
signature = bytes()
|
||||||
for i in domain.split('.'):
|
for i in zone.split('.'):
|
||||||
signature += pack('B', len(i)) + i.encode()
|
signature += pack('B', len(i)) + i.encode()
|
||||||
|
|
||||||
signature += pack('!HBB', int(flags), int(protocol), int(algorithm))
|
signature += pack('!HBB', int(flags), int(protocol), int(algorithm))
|
||||||
|
@ -103,8 +104,27 @@ def _calc_keyid(flags, protocol, algorithm, dnskey):
|
||||||
|
|
||||||
return ((cnt & 0xFFFF) + (cnt >> 16)) & 0xFFFF
|
return ((cnt & 0xFFFF) + (cnt >> 16)) & 0xFFFF
|
||||||
|
|
||||||
keyid = _calc_keyid(flags, protocol, algorithm, dnskey)
|
def dnskey_to_ds(zone, flags, protocol, algorithm, dnskey):
|
||||||
ds = _calc_ds(domain, flags, protocol, algorithm, dnskey)
|
keyid = _calc_keyid(flags, protocol, algorithm, dnskey)
|
||||||
|
ds = _calc_ds(zone, flags, protocol, algorithm, dnskey)
|
||||||
|
|
||||||
print(f"{domain}. IN DS {str(keyid)} {str(algorithm)} 1 {ds['sha1'].lower()}")
|
return[
|
||||||
print(f"{domain}. IN DS {str(keyid)} {str(algorithm)} 2 {ds['sha256'].lower()}")
|
f"{zone}. IN DS {str(keyid)} {str(algorithm)} 1 {ds['sha1'].lower()}",
|
||||||
|
f"{zone}. IN DS {str(keyid)} {str(algorithm)} 2 {ds['sha256'].lower()}",
|
||||||
|
]
|
||||||
|
|
||||||
|
def generate_dnssec_for_zone(zone):
|
||||||
|
zsk_data = generate_signing_key_pair(zone, salt='zsk')
|
||||||
|
ksk_data = generate_signing_key_pair(zone, salt='ksk')
|
||||||
|
ds_records = dnskey_to_ds(zone, flags, protocol, algorithm, ksk_data['dnskey'])
|
||||||
|
|
||||||
|
return {
|
||||||
|
'zsk_data': zsk_data,
|
||||||
|
'ksk_data': ksk_data,
|
||||||
|
'ds_records': ds_records,
|
||||||
|
}
|
||||||
|
|
||||||
|
print(dumps(
|
||||||
|
generate_dnssec_for_zone(zone),
|
||||||
|
indent=4,
|
||||||
|
))
|
||||||
|
|
Loading…
Reference in a new issue