#!/usr/bin/perl -w # -*- perl -*- # gpgkeys_jkp - talk to a DNS server # Copyright (C) 2002 Simon Josefsson # # This file is not part of GnuPG, but the same permissions apply. # # GnuPG is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # GnuPG 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, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA # Revision history: # 2002-07-07 1.0 initial release # 2002-08-03 1.2 cosmetic changes, synchronized release with CKS-DNS 1.0 use Getopt::Std; use Net::DNS; use MIME::Base64; my ($CRC24_INIT) = 0x00b704ce; my ($CRC24_POLY) = 0x00864cfb; sub crc24 { my ($data) = @_; my ($crc) = $CRC24_INIT; my ($position) = 0; my ($string_length) = length($data); while ( $position < $string_length ) { $crc ^= (unpack("C", substr($data, $position, 1)) << 16); my ($i); for ($i = 0; $i < 8; $i++) { $crc <<= 1; $crc ^= $CRC24_POLY if ($crc & 0x01000000) } $position++; } return $crc & 0x00ffffff; } getopts('o:'); if(defined($opt_o)) { open(STDOUT,">$opt_o") || die "Can't open output file $opt_o\n"; } if(@ARGV) { open(STDIN,$ARGV[0]) || die "Can't open input file $ARGV[0]\n"; } while() { last if($_ eq "\n"); if(/^COMMAND (\w+)/) { $command=$1; } if(/^HOST (\S+)/) { $host=$1; } if(/^OPTION (\w+)/) { if($1=~/^verbose$/i) { $verbose++; } elsif($1=~/^no-verbose$/i) { $verbose--; } } } while() { last if($_ eq "\n"); chomp; push(@keys,$_); } # Send response print "VERSION 0\n"; print "\n"; my $res = Net::DNS::Resolver->new; # $res->usevc(1); if($command=~/get/i) { foreach $key (@keys) { print "KEY $key BEGIN\n"; my $okey = $key; if($verbose) { print STDERR "gpgkeys: requesting key $key from jkp://$host:\n"; } if(substr($key,0,2) eq "0x") { $key=substr($key,2); } if(length($key)>8) { $key=substr($key,-8); } $key="0x" . $key; my $query = $res->query("$key.$host", "CERT"); if ($query) { my $str = ($query->answer)[0]->rdata; $str = substr($str,5); print "-----BEGIN PGP PUBLIC KEY BLOCK-----\n"; print "\n"; print encode_base64($str); print "=" . encode_base64(substr(pack("N", crc24($str)), 1, 3)) . "\n"; print "-----END PGP PUBLIC KEY BLOCK-----\n"; print "KEY $okey END\n"; if($verbose) { print STDERR "gpgkeys: key $key retrieved from $host\n"; } } else { if($verbose) { print STDERR "gpgkeys: key $key not found on $host\n"; } } } } if($command=~/send/i) { while(!eof(STDIN)) { while() { if(/^KEY (\w+) BEGIN$/) { $key=$1; last; } } $keydata = ""; $inheader = 1; while() { if(/^KEY \w+ END$/) { last; } if(/^$/) { $inheader = 0; } if(/-----END PGP PUBLIC KEY BLOCK-----/) { $inheader = 1; } next if $inheader; next if(/^=/); # crc24 junk chomp; $keydata .= $_; } if($verbose) { print STDERR "gpgkeys: sending key $key to $host\n"; } if(substr($key,0,2) eq "0x") { $key=substr($key,2); } if(length($key)>8) { $key=substr($key,-8); } $key = "0x" . $key; $packet = Net::DNS::Update->new($host, "IN"); my $query = $res->query($host, "NS"); my @ns; if ($query) { foreach $rr ($query->answer) { next unless $rr->type eq "NS"; print $rr->nsdname, "\n"; push @ns, $rr->nsdname; } } else { print "query failed: ", $res->errorstring, "\n"; } $done = 0; $packet->push("update", rr_add("$key.$host. CERT PGP 0 0 $keydata")); while (!$done && @ns) { my $ns = pop @ns; if ($verbose) { print STDERR "gpgkeys: trying server $ns\n"; } $res->nameservers($ns); my $reply = $res->send($packet); if (defined $reply) { if ($reply->header->rcode eq "NOERROR") { $done = 1; } else { print STDERR "gpgkeys: update on $ns failed: ", $reply->header->rcode, "\n"; } } else { print STDERR "gpgkeys: communication error with $ns: ", $res->errorstring, "\n"; } } if ($verbose) { if (!$done) { print STDERR "gpgkeys: all servers failed\n"; } else { print STDERR "gpgkeys: key $key sent to $host\n"; } } } }