7 use POSIX
qw(mktime strftime setlocale LC_COLLATE);
9 setlocale
(LC_COLLATE
, "en_US.UTF-8");
11 my $page = 'https://openwrt.org/docs/guide-user/security/signatures';
30 'Elgamal, encrypt only',
40 if ($key->{is_system_key
}) {
41 return $key->{comment
};
44 return sprintf 'Public key of %s', $key->{name
};
48 my ($key, $is_subkey) = @_;
50 my $type = $key->{$is_subkey ?
'stype' : 'type'};
51 my $size = $key->{$is_subkey ?
'ssize' : 'size'};
55 if (defined($size) && $size > 0) {
56 $s = sprintf '%d Bit %s', $size, $keytypes[$type];
59 $s = $keytypes[$type];
62 (undef, undef, undef, $d, $m, $y) =
63 localtime $key->{$is_subkey ?
'sctime' : 'ctime'};
65 $s .= sprintf ', created %04d-%02d-%02d', $y + 1900, $m + 1, $d;
67 (undef, undef, undef, $d, $m, $y) =
68 localtime $key->{$is_subkey ?
'setime' : 'etime'};
71 $s .= sprintf ', expires %04d-%02d-%02d', $y + 1900, $m + 1, $d;
77 sub format_fingerprint
{
78 my ($key, $is_subkey) = @_;
80 my $fprint = $key->{$is_subkey ?
'sfprint' : 'fprint'};
81 my (@fields) = $fprint =~ m!([A-F0-9]{4})!g;
83 return join(' ', @fields[0..4]) . ' ' . join(' ', @fields[5..9]);
89 my $mtime = $key->{ctime
};
91 if (open GIT
, '-|', qw(git log -1 --format=%ct --), $key->{filename}) {
92 if (defined(my $line = readline GIT)) {
99 my $ts = strftime '%F %T %z', gmtime $mtime;
102 "[[https://git.openwrt.org/?p=keyring.git;a=history;f=%s|Last change: %s]] | " .
103 "[[https://git.openwrt.org/?p=keyring.git;a=blob_plain;f=%s|Download]]\n" ,
104 $key->{filename}, $ts, $key->{filename};
107 sub parse_timestamp {
110 if ($s =~ m!^(\d\d\d\d)-(\d\d)-(\d\d)$!) {
111 return mktime(0, 0, 0, $3 + 0, $2 - 1, $1 - 1900);
118 my $markup_template = '';
120 if (open RAW, '-|', 'curl', '-s', "$page?do=export_raw") {
122 $markup_template = readline RAW;
129 if (open KEYS, '-|', qw(find gpg/ -type f -name *.asc -print)) {
130 while (defined(my $file = readline KEYS
)) {
132 if (open GPG
, '-|', qw(gpg --with-fingerprint --with-fingerprint --with-colons), $file) {
135 while (defined(my $line = readline GPG
)) {
137 my @fields = split ':', $line;
138 if ($fields[0] eq 'uid' && !exists $data{name
}) {
139 ($data{name
}, $data{comment
}, $data{email
}) =
140 $fields[9] =~ m!^([^()]+)(?: \((.+?)\))? <(.+)>$!;
142 elsif ($fields[0] eq 'pub') {
143 $data{size
} = int $fields[2];
144 $data{type
} = int $fields[3];
145 $data{eid
} = $fields[4];
146 $data{ctime
} = parse_timestamp
($fields[5]);
147 $data{etime
} = $fields[6] ? parse_timestamp
($fields[6]) : 0;
148 if ($fields[9] && !exists $data{name
}) {
149 ($data{name
}, $data{comment
}, $data{email
}) =
150 $fields[9] =~ m!^([^()]+)(?: \((.+?)\))? <(.+)>$!;
153 elsif ($fields[0] eq 'sub') {
154 $data{ssize
} = int $fields[2];
155 $data{stype
} = int $fields[3];
156 $data{seid
} = $fields[4];
157 $data{sctime
} = parse_timestamp
($fields[5]);
158 $data{setime
} = $fields[6] ? parse_timestamp
($fields[6]) : 0;
160 elsif ($fields[0] eq 'fpr') {
161 $data{exists($data{stype
}) ?
'sfprint' : 'fprint'} = $fields[9];
167 $data{filename
} = $file;
168 $data{is_system_key
} =
169 (index($data{email
}, 'openwrt.org') >= 0) ||
170 (index($data{email
}, 'lede-project.org') >= 0) ||
171 (index($data{email
}, 'lists.openwrt.org') >= 0) ||
172 (index($data{email
}, 'lists.infradead.org') >= 0);
174 push @pubkeys, \
%data;
183 foreach my $key (sort {
184 !$a->{is_system_key
} <=> !$b->{is_system_key
} ||
185 $a->{name
} cmp $b->{name
}
188 $gpg_markup .= sprintf "---\n\n=== %s ===\n\n",
191 $gpg_markup .= sprintf "User ID: **%s** <%s>\\\\\n",
192 $key->{name
}, $key->{email
};
194 $gpg_markup .= sprintf "Public Key: 0x%s**%s** (%s)\\\\\n",
195 substr($key->{eid
}, 0, 8), substr($key->{eid
}, 8),
196 format_keytype
($key, 0);
198 $gpg_markup .= sprintf "Fingerprint: ''%%%%%s%%%%''\\\\\n",
199 format_fingerprint
($key, 0);
201 if (exists $key->{stype
}) {
202 $gpg_markup .= sprintf "Signing Subkey: 0x%s **%s** (%s)\\\\\n",
203 substr($key->{seid
}, 0, 8), substr($key->{seid
}, 8),
204 format_keytype
($key, 1);
206 $gpg_markup .= sprintf "Fingerprint: ''%%%%%s%%%%''\\\\\n",
207 format_fingerprint
($key, 1);
210 $gpg_markup .= sprintf "%s\n", format_download
($key);
216 if (open KEYS
, '-|', qw(find usign/ -type f -name *[0-9a-f] -print)) {
217 while (defined(my $file = readline KEYS
)) {
220 if (open USIGN
, '<', $file) {
223 while (defined(my $line = readline USIGN
)) {
226 if ($line =~ m!^untrusted comment: (.+)$!) {
236 $file =~ m!/([0-9a-f]{16})$!;
239 $data{filename
} = $file;
241 push @usignkeys, \
%data;
248 my $usign_markup = '';
250 foreach my $key (sort { $a->{comment
} cmp $b->{comment
} } @usignkeys) {
251 $usign_markup .= sprintf "---\n\n=== %s ===\n\n",
254 $usign_markup .= sprintf " * Key-ID: ''%%%%%s%%%%''\n",
257 $usign_markup .= sprintf " * Key-Data: ''%%%%%s%%%%''\n\n",
260 $usign_markup .= sprintf "%s\n",
261 format_download
($key);
265 $markup_template =~ s
!
266 ( /\*\sBEGIN\sGPG\sKEYS\s\*/ )
268 ( /\*\sEND\sGPG\sKEYS\s\*/ )
270 $1 . "\n\n" . $gpg_markup . $2;
273 $markup_template =~ s
!
274 ( /\*\sBEGIN\sUSIGN\sKEYS\s\*/ )
276 ( /\*\sEND\sUSIGN\sKEYS\s\*/ )
278 $1 . "\n\n" . $usign_markup . $2;
282 print $markup_template;