1 /* pka.c - DNS Public Key Association RR access
2 * Copyright (C) 2005 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
27 #include <sys/types.h>
31 #include <netinet/in.h>
32 #include <arpa/nameser.h>
35 #endif /* USE_DNS_PKA */
41 /* Parse the TXT resource record. Format is:
43 v=pka1;fpr=a4d94e92b0986ab5ee9dcd755de249965b0358a2;uri=string
45 For simplicity white spaces are not allowed. Because we expect to
46 use a new RRTYPE for this in the future we define the TXT really
47 strict for simplicity: No white spaces, case sensitivity of the
48 names, order must be as given above. Only URI is optional.
50 This function modifies BUFFER. On success 0 is returned, the 20
51 byte fingerprint stored at FPR and BUFFER contains the URI or an
55 parse_txt_record (char *buffer
, unsigned char *fpr
)
61 pend
= strchr (p
, ';');
65 if (strcmp (p
, "v=pka1"))
66 return -1; /* Wrong or missing version. */
69 pend
= strchr (p
, ';');
72 if (strncmp (p
, "fpr=", 4))
73 return -1; /* Missing fingerprint part. */
75 for (i
=0; i
< 20 && hexdigitp (p
) && hexdigitp (p
+1); i
++, p
+= 2)
78 return -1; /* Fingerprint consists not of exactly 40 hexbytes. */
84 return 0; /* Success (no URI given). */
86 if (strncmp (p
, "uri=", 4))
87 return -1; /* Unknown part. */
89 /* There is an URI, copy it to the start of the buffer. */
97 /* For the given email ADDRESS lookup the PKA information in the DNS.
99 On success the 20 byte SHA-1 fingerprint is stored at FPR and the
100 URI will be returned in an allocated buffer. Note that the URI
101 might be an zero length string as this information is optional.
102 Caller must xfree the returned string.
104 On error NULL is returned and the 20 bytes at FPR are not
107 get_pka_info (const char *address
, unsigned char *fpr
)
109 unsigned char answer
[PACKETSZ
];
111 int qdcount
, ancount
, nscount
, arcount
;
113 unsigned char *p
, *pend
;
118 domain
= strrchr (address
, '@');
119 if (!domain
|| domain
== address
|| !domain
[1])
120 return NULL
; /* invalid mail address given. */
122 name
= xtrymalloc (strlen (address
) + 5 + 1);
125 memcpy (name
, address
, domain
- address
);
126 strcpy (stpcpy (name
+ (domain
-address
), "._pka."), domain
+1);
128 anslen
= res_query (name
, C_IN
, T_TXT
, answer
, PACKETSZ
);
130 if (anslen
< sizeof(HEADER
))
131 return NULL
; /* DNS resolver returned a too short answer. */
132 if ( (rc
=((HEADER
*)answer
)->rcode
) != NOERROR
)
133 return NULL
; /* DNS resolver returned an error. */
135 /* We assume that PACKETSZ is large enough and don't do dynmically
136 expansion of the buffer. */
137 if (anslen
> PACKETSZ
)
138 return NULL
; /* DNS resolver returned a too long answer */
140 qdcount
= ntohs (((HEADER
*)answer
)->qdcount
);
141 ancount
= ntohs (((HEADER
*)answer
)->ancount
);
142 nscount
= ntohs (((HEADER
*)answer
)->nscount
);
143 arcount
= ntohs (((HEADER
*)answer
)->arcount
);
146 return NULL
; /* Got no answer. */
148 p
= answer
+ sizeof (HEADER
);
149 pend
= answer
+ anslen
; /* Actually points directly behind the buffer. */
151 while (qdcount
-- && p
< pend
)
153 rc
= dn_skipname (p
, pend
);
160 return NULL
; /* more than one possible gpg trustdns record - none used. */
162 while (ancount
-- && p
<= pend
)
164 unsigned int type
, class, txtlen
, n
;
167 rc
= dn_skipname (p
, pend
);
172 return NULL
; /* RR too short. */
181 if (type
!= T_TXT
|| class != C_IN
)
182 return NULL
; /* Answer does not match the query. */
184 buffer
= bufp
= xmalloc (txtlen
+ 1);
185 while (txtlen
&& p
< pend
)
187 for (n
= *p
++, txtlen
--; txtlen
&& n
&& p
< pend
; txtlen
--, n
--)
191 if (parse_txt_record (buffer
, fpr
))
194 return NULL
; /* Not a valid gpg trustdns RR. */
201 #else /* !USE_DNS_PKA */
203 /* Dummy version of the function if we can't use the resolver
206 get_pka_info (const char *address
, unsigned char *fpr
)
210 #endif /* !USE_DNS_PKA */
215 main(int argc
,char *argv
[])
217 unsigned char fpr
[20];
223 fprintf (stderr
, "usage: pka mail-addresses\n");
229 for (; argc
; argc
--, argv
++)
231 uri
= get_pka_info ( *argv
, fpr
);
232 printf ("%s", *argv
);
236 for (i
=0; i
< 20; i
++)
237 printf ("%02X", fpr
[i
]);
250 compile-command: "cc -DUSE_DNS_PKA -DTEST -I.. -I../include -Wall -g -o pka pka.c -lresolv libutil.a"