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 optiobnal.
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
= malloc (strlen (address
) + 5 + 1);
123 memcpy (name
, address
, domain
- address
);
124 strcpy (stpcpy (name
+ (domain
-address
), "._pka."), domain
+1);
126 anslen
= res_query (name
, C_IN
, T_TXT
, answer
, PACKETSZ
);
128 if (anslen
< sizeof(HEADER
))
129 return NULL
; /* DNS resolver returned a too short answer. */
130 if ( (rc
=((HEADER
*)answer
)->rcode
) != NOERROR
)
131 return NULL
; /* DNS resolver returned an error. */
133 /* We assume that PACKETSZ is large enough and don't do dynmically
134 expansion of the buffer. */
135 if (anslen
> PACKETSZ
)
136 return NULL
; /* DNS resolver returned a too long answer */
138 qdcount
= ntohs (((HEADER
*)answer
)->qdcount
);
139 ancount
= ntohs (((HEADER
*)answer
)->ancount
);
140 nscount
= ntohs (((HEADER
*)answer
)->nscount
);
141 arcount
= ntohs (((HEADER
*)answer
)->arcount
);
144 return NULL
; /* Got no answer. */
146 p
= answer
+ sizeof (HEADER
);
147 pend
= answer
+ anslen
; /* Actually points directly behind the buffer. */
149 while (qdcount
-- && p
< pend
)
151 rc
= dn_skipname (p
, pend
);
158 return NULL
; /* more than one possible gpg trustdns record - none used. */
160 while (ancount
-- && p
<= pend
)
162 unsigned int type
, class, txtlen
, n
;
165 rc
= dn_skipname (p
, pend
);
170 return NULL
; /* RR too short. */
179 if (type
!= T_TXT
|| class != C_IN
)
180 return NULL
; /* Answer does not match the query. */
182 buffer
= bufp
= xmalloc (txtlen
+ 1);
183 while (txtlen
&& p
< pend
)
185 for (n
= *p
++, txtlen
--; txtlen
&& n
&& p
< pend
; txtlen
--, n
--)
189 if (parse_txt_record (buffer
, fpr
))
192 return NULL
; /* Not a valid gpg trustdns RR. */
199 #else /* !USE_DNS_PKA */
201 /* Dummy version of the function if we can't use the resolver
204 get_pka_info (const char *address
, unsigned char *fpr
)
208 #endif /* !USE_DNS_PKA */
213 main(int argc
,char *argv
[])
215 unsigned char fpr
[20];
221 fprintf (stderr
, "usage: pka mail-addresses\n");
227 for (; argc
; argc
--, argv
++)
229 uri
= get_pka_info ( *argv
, fpr
);
230 printf ("%s", *argv
);
234 for (i
=0; i
< 20; i
++)
235 printf ("%02X", fpr
[i
]);
248 compile-command: "cc -DUSE_DNS_PKA -DTEST -I.. -I../include -Wall -g -o pka pka.c -lresolv libutil.a"