-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtinydkim.py
More file actions
executable file
·126 lines (108 loc) · 3.46 KB
/
tinydkim.py
File metadata and controls
executable file
·126 lines (108 loc) · 3.46 KB
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env python3
# tinydkim - takes an RSA public key on stdin and outputs a tinydns / djbdns DKIM record
#
# example: openssl rsa -in test.pem -pubout | ./tinydkim.py -s test -d foo.com
#
# TODO: add support for notes field?
#
# https://www.rfc-editor.org/rfc/rfc6376.html
#
# 2016,2022 Lee Maguire
import getopt
import sys
import re
bind = ''
opt_h = ''
opt_t = ''
ttl = "86400"
selector = "selector"
domain = "example.com"
def extractPubKey( key ):
output = ""
key = key.replace('-----BEGIN PUBLIC KEY-----','')
key = key.replace('-----END PUBLIC KEY-----','')
key = key.replace('-----BEGIN RSA PUBLIC KEY-----','')
key = key.replace('-----END RSA PUBLIC KEY-----','')
for c in key:
if not c in ["\r","\n","\t"," "]:
output = output + c
return( output );
def tinyBytes( bytearr, escape_all=False ):
## output printable ascii but not space, "/", ":", "\"
## all other characters output as octal \nnn codes
output = ""
for b in bytearr:
if not escape_all and int(b) > 32 and int(b) < 127 and int(b) not in [47,58,92]:
output += chr(b)
else:
output += "\\{0:03o}".format(b)
return( output )
def nboInt( length, number ):
## returns bytes representing an integer in network byte order (big endian)
## if input "2, 256", output should be equivalent to "\001\000"
intbytes = int(number).to_bytes(length, "big")
return( intbytes )
def tinyTxtRecord( domain, record, ttl ):
output = "'"
output += tinyBytes( bytes(domain, "ascii") )
output += ":"
output += tinyBytes( bytes(record, "ascii"))
output += ":" + ttl
return( output )
def tinyDkimRecord( domain, record, ttl ):
output = ":"
output += tinyBytes( bytes(domain, "ascii") )
output += ":16:"
output += "\\{0:03o}".format( len(record) )
output += tinyBytes( bytes(record, "ascii"))
output += ":" + ttl
return( output )
def dnsQuotedText( text ):
output = ""
for c in text:
if c in [";"]:
output = output + "\\;"
else:
output = output + c
output = "\"" + output + "\""
return( output );
def dnsTxtRecord( domain, record, ttl ):
output = domain + ". " + ttl + " IN TXT " + dnsQuotedText( record );
return( output )
opts, args = getopt.getopt(sys.argv[1:],"hs:d:t:l:bx",["selector=","domain=","hash=","testing=","ttl=","bind","text"])
for opt, arg in opts:
if opt == '-h':
print('Usage: tinydkim.py -s selector -d example.com -t y < pubkey.pem')
sys.exit()
elif opt in ("-s", "--selector"):
selector = arg
elif opt in ("-d", "--domain"):
domain = arg
elif opt in ("-h", "--hash"):
opt_h = arg
elif opt in ("-t", "--testing"):
opt_t = arg
elif opt in ("-l", "--ttl"):
ttl = arg
elif opt in ("-x", "--text"):
text_record = 1
elif opt in ("-b", "--bind"):
bind = 1
input_text = "".join(sys.stdin)
rdata = "v=DKIM1"
if opt_h:
rdata = rdata + "; h=" + opt_h
rdata = rdata + "; p=" + extractPubKey( input_text )
if opt_t:
rdata = rdata + "; t=" + opt_t
fqdn = selector + "._domainkey." + domain
if text_record:
line = tinyTxtRecord( fqdn, rdata, ttl )
else:
line = tinyDkimRecord( fqdn, rdata, ttl )
sys.stdout.write( line + "\n")
## optionally output the format used by lookup tools for comparison
if bind:
line = dnsTxtRecord( fqdn, rdata, ttl )
sys.stdout.write( "\n# " + line + "\n" )
sys.exit(0)