common: Minor change of hex2str to allow for embedded nul.
[gnupg.git] / common / dns-cert.c
index 7c1b9c6..405ca29 100644 (file)
@@ -31,6 +31,9 @@
 #include <sys/types.h>
 #ifdef USE_DNS_CERT
 # ifdef HAVE_W32_SYSTEM
+#  ifdef HAVE_WINSOCK2_H
+#   include <winsock2.h>
+#  endif
 #  include <windows.h>
 # else
 #  include <netinet/in.h>
 #endif
 #ifdef USE_ADNS
 # include <adns.h>
-# ifndef HAVE_ADNS_FREE
-#  define adns_free free
-# endif
 #endif
 
 #include "util.h"
+#include "host2net.h"
 #include "dns-cert.h"
 
 /* Not every installation has gotten around to supporting CERTs
 #define my_adns_r_cert 37
 
 
-/* Certificate types according to RFC-4398.  */
-#define CERTTYPE_PKIX      1 /* X.509 as per PKIX. */
-#define CERTTYPE_SPKI      2 /* SPKI certificate.  */
-#define CERTTYPE_PGP       3 /* OpenPGP packet.  */
-#define CERTTYPE_IPKIX     4 /* The URL of an X.509 data object. */
-#define CERTTYPE_ISPKI     5 /* The URL of an SPKI certificate.  */
-#define CERTTYPE_IPGP      6 /* The fingerprint and URL of an OpenPGP packet.*/
-#define CERTTYPE_ACPKIX    7 /* Attribute Certificate.  */
-#define CERTTYPE_IACPKIX   8 /* The URL of an Attribute Certificate.  */
-#define CERTTYPE_URI     253 /* URI private.  */
-#define CERTTYPE_OID     254 /* OID private.  */
-
 
 /* Returns 0 on success or an error code.  If a PGP CERT record was
    found, a new estream with that key will be returned at R_KEY and
    the other return parameters are set to NULL/0.  If an IPGP CERT
    record was found the fingerprint is stored as an allocated block at
    R_FPR and its length at R_FPRLEN; an URL is is allocated as a
-   string and returned at R_URL.  Note that this function returns the
-   first CERT found with a supported type; it is expected that only
-   one CERT record is used. */
+   string and returned at R_URL.  If WANT_CERTTYPE is 0 this function
+   returns the first CERT found with a supported type; it is expected
+   that only one CERT record is used.  If WANT_CERTTYPE is one of the
+   supported certtypes only records wih this certtype are considered
+   and the first found is returned.  R_KEY is optional. */
 gpg_error_t
-get_dns_cert (const char *name, estream_t *r_key,
+get_dns_cert (const char *name, int want_certtype,
+              estream_t *r_key,
               unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
 {
 #ifdef USE_DNS_CERT
@@ -92,7 +84,8 @@ get_dns_cert (const char *name, estream_t *r_key,
   unsigned int ctype;
   int count;
 
-  *r_key = NULL;
+  if (r_key)
+    *r_key = NULL;
   *r_fpr = NULL;
   *r_fprlen = 0;
   *r_url = NULL;
@@ -130,12 +123,14 @@ get_dns_cert (const char *name, estream_t *r_key,
       if (datalen < 5)
         continue;  /* Truncated CERT record - skip.  */
 
-      ctype = ((data[0] << 8) | data[1]);
+      ctype = buf16_to_uint (data);
       /* (key tag and algorithm fields are not required.) */
       data += 5;
       datalen -= 5;
 
-      if (ctype == CERTTYPE_PGP && datalen >= 11)
+      if (want_certtype && want_certtype != ctype)
+        ; /* Not of the requested certtype.  */
+      else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key)
         {
           /* CERT type is PGP.  Gpg checks for a minimum length of 11,
              thus we do the same.  */
@@ -147,7 +142,7 @@ get_dns_cert (const char *name, estream_t *r_key,
             err = 0;
           goto leave;
         }
-      else if (ctype == CERTTYPE_IPGP && datalen && datalen < 1023
+      else if (ctype == DNS_CERTTYPE_IPGP && datalen && datalen < 1023
                && datalen >= data[0] + 1 && r_fpr && r_fprlen && r_url)
         {
           /* CERT type is IPGP.  We made sure that the data is
@@ -203,7 +198,8 @@ get_dns_cert (const char *name, estream_t *r_key,
   int r;
   u16 count;
 
-  *r_key = NULL;
+  if (r_key)
+    *r_key = NULL;
   *r_fpr = NULL;
   *r_fprlen = 0;
   *r_url = NULL;
@@ -262,12 +258,12 @@ get_dns_cert (const char *name, estream_t *r_key,
           if ((emsg - pt) < 15)
             break;
 
-          type = *pt++ << 8;
-          type |= *pt++;
+          type = buf16_to_u16 (pt);
+          pt += 2;
+
+          class = buf16_to_u16 (pt);
+          pt += 2;
 
-          class = *pt++ << 8;
-          class |= *pt++;
-          /* We asked for IN and got something else !? */
           if (class != C_IN)
             break;
 
@@ -275,8 +271,8 @@ get_dns_cert (const char *name, estream_t *r_key,
           pt += 4;
 
           /* data length */
-          dlen = *pt++ << 8;
-          dlen |= *pt++;
+          dlen = buf16_to_u16 (pt);
+          pt += 2;
 
           /* We asked for CERT and got something else - might be a
              CNAME, so loop around again. */
@@ -287,8 +283,8 @@ get_dns_cert (const char *name, estream_t *r_key,
             }
 
           /* The CERT type */
-          ctype = *pt++ << 8;
-          ctype |= *pt++;
+          ctype = buf16_to_u16 (pt);
+          pt += 2;
 
           /* Skip the CERT key tag and algo which we don't need. */
           pt += 3;
@@ -296,8 +292,9 @@ get_dns_cert (const char *name, estream_t *r_key,
           dlen -= 5;
 
           /* 15 bytes takes us to here */
-
-          if (ctype == CERTTYPE_PGP && dlen)
+          if (want_certtype && want_certtype != ctype)
+            ; /* Not of the requested certtype.  */
+          else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key)
             {
               /* PGP type */
               *r_key = es_fopenmem_init (0, "rwb", pt, dlen);
@@ -308,7 +305,7 @@ get_dns_cert (const char *name, estream_t *r_key,
                 err = 0;
               goto leave;
             }
-          else if (ctype == CERTTYPE_IPGP
+          else if (ctype == DNS_CERTTYPE_IPGP
                    && dlen && dlen < 1023 && dlen >= pt[0] + 1)
             {
               /* IPGP type */
@@ -360,7 +357,8 @@ get_dns_cert (const char *name, estream_t *r_key,
 #endif /*!USE_ADNS */
 #else /* !USE_DNS_CERT */
   (void)name;
-  *r_key = NULL;
+  if (r_key)
+    *r_key = NULL;
   *r_fpr = NULL;
   *r_fprlen = 0;
   *r_url = NULL;