NTBTLS: verification of certificate

NIIBE Yutaka gniibe at fsij.org
Fri Jan 20 11:19:43 CET 2017


Hello,

I am testing following code with dirmngr in master (and ntbtls of
master).

I confirmed that two hosts work fine.

    https://host-37-191-238-78.lynet.no
    https://gpg.nebrwesleyan.edu

==========================
diff --git a/src/pkglue.c b/src/pkglue.c
index 45f388b..33613d3 100644
--- a/src/pkglue.c
+++ b/src/pkglue.c
@@ -77,6 +77,156 @@ pk_algo_from_sexp (gcry_sexp_t pkey)
 }
 
 
+/* Copied from gpgsm */
+/* Hash function used with libksba. */
+#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
+
+static int
+do_encode_md (gcry_md_hd_t md, int algo, int pkalgo, unsigned int nbits,
+              gcry_sexp_t pkey, gcry_mpi_t *r_val)
+{
+  int n;
+  size_t nframe;
+  unsigned char *frame;
+
+  if (pkalgo == GCRY_PK_DSA || pkalgo == GCRY_PK_ECDSA)
+    return gpg_error (GPG_ERR_INTERNAL);
+  else
+    {
+      int i;
+      unsigned char asn[100];
+      size_t asnlen;
+      size_t len;
+
+      nframe = (nbits+7) / 8;
+
+      asnlen = DIM(asn);
+      if (!algo || gcry_md_test_algo (algo))
+        return gpg_error (GPG_ERR_DIGEST_ALGO);
+      if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
+        {
+          return gpg_error (GPG_ERR_INTERNAL);
+        }
+
+      len = gcry_md_get_algo_dlen (algo);
+
+      if ( len + asnlen + 4  > nframe )
+        {
+          return gpg_error (GPG_ERR_INTERNAL);
+        }
+
+      /* We encode the MD in this way:
+       *
+       *	   0  A PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
+       *
+       * PAD consists of FF bytes.
+       */
+      frame = malloc (nframe);
+      if (!frame)
+        return gpg_error (GPG_ERR_INTERNAL);
+      n = 0;
+      frame[n++] = 0;
+      frame[n++] = 1; /* block type */
+      i = nframe - len - asnlen -3 ;
+      // assert ( i > 1 );
+      memset ( frame+n, 0xff, i ); n += i;
+      frame[n++] = 0;
+      memcpy ( frame+n, asn, asnlen ); n += asnlen;
+      memcpy ( frame+n, gcry_md_read(md, algo), len ); n += len;
+      // assert ( n == nframe );
+    }
+
+  gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, n, &nframe);
+  free (frame);
+  return 0;
+}
+
+/* Copied from gpgsm */
+gpg_error_t
+_ntbtls_x509_check_cert_sig (ksba_cert_t issuer_cert, ksba_cert_t cert)
+{
+  gpg_error_t err;
+  const char *algoid;
+  gcry_md_hd_t md;
+  int algo;
+  gcry_mpi_t frame;
+  ksba_sexp_t p;
+  size_t n;
+  gcry_sexp_t s_sig, s_hash, s_pkey;
+
+  algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert)));
+  if (!algo)
+    return gpg_error (GPG_ERR_GENERAL);
+
+  err = gcry_md_open (&md, algo, 0);
+  if (err)
+    return err;
+
+  err = ksba_cert_hash (cert, 1, HASH_FNC, md);
+  if (err)
+    {
+      gcry_md_close (md);
+      return err;
+    }
+  gcry_md_final (md);
+
+  p = ksba_cert_get_sig_val (cert);
+  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+  if (!n)
+    {
+      gcry_md_close (md);
+      ksba_free (p);
+      return gpg_error (GPG_ERR_BUG);
+    }
+
+  err = gcry_sexp_sscan ( &s_sig, NULL, (char*)p, n);
+  ksba_free (p);
+  if (err)
+    {
+      gcry_md_close (md);
+      return err;
+    }
+
+  p = ksba_cert_get_public_key (issuer_cert);
+  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+  if (!n)
+    {
+      gcry_md_close (md);
+      ksba_free (p);
+      gcry_sexp_release (s_sig);
+      return gpg_error (GPG_ERR_BUG);
+    }
+  err = gcry_sexp_sscan ( &s_pkey, NULL, (char*)p, n);
+  ksba_free (p);
+  if (err)
+    {
+      gcry_md_close (md);
+      gcry_sexp_release (s_sig);
+      return err;
+    }
+
+  err = do_encode_md (md, algo, pk_algo_from_sexp (s_pkey),
+		      gcry_pk_get_nbits (s_pkey), s_pkey, &frame);
+  if (err)
+    {
+      gcry_md_close (md);
+      gcry_sexp_release (s_sig);
+      gcry_sexp_release (s_pkey);
+      return err;
+    }
+
+  /* put hash into the S-Exp s_hash */
+  gcry_sexp_build (&s_hash, NULL, "%m", frame);
+  gcry_mpi_release (frame);
+
+  err = gcry_pk_verify (s_sig, s_hash, s_pkey);
+  gcry_md_close (md);
+  gcry_sexp_release (s_sig);
+  gcry_sexp_release (s_hash);
+  gcry_sexp_release (s_pkey);
+  return err;
+}
+
 gpg_error_t
 _ntbtls_pk_verify (x509_cert_t chain, pk_algo_t pk_alg, md_algo_t md_alg,
                    const unsigned char *hash, size_t hashlen,
diff --git a/src/protocol.c b/src/protocol.c
index f616bca..9b5659d 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -2007,7 +2007,7 @@ _ntbtls_read_certificate (ntbtls_t tls)
                                  tls->ca_chain, tls->ca_crl,
                                  tls->hostname,
                                  &tls->session_negotiate->verify_result);
-      if (err)
+      if (1 || err)
         {
           debug_ret (1, "x509_verify", err);
         }
@@ -2036,9 +2036,6 @@ _ntbtls_read_certificate (ntbtls_t tls)
       /*     if (!err) */
       /*       err = gpg_error (GPG_ERR_BAD_HS_CERT); */
       /*   } */
-
-      if (tls->authmode != TLS_VERIFY_REQUIRED)
-        err = 0;
     }
 
   return err;
@@ -2635,6 +2632,8 @@ _ntbtls_new (ntbtls_t *r_tls, unsigned int flags)
   if (!tls)
     return gpg_error_from_syserror ();  /* Return immediately.  */
 
+  ssl_set_authmode (tls, TLS_VERIFY_OPTIONAL);
+
   tls->min_major_ver = TLS_MIN_MAJOR_VERSION;
   tls->min_minor_ver = TLS_MIN_MINOR_VERSION;
   tls->max_major_ver = TLS_MAX_MAJOR_VERSION;
diff --git a/src/x509.c b/src/x509.c
index 595839d..70d063c 100644
--- a/src/x509.c
+++ b/src/x509.c
@@ -187,14 +187,71 @@ _ntbtls_x509_get_pk (x509_cert_t cert, int idx, gcry_sexp_t *r_pk)
 }
 
 
+/* Check if PARENT verifies CHILD */
+static gpg_error_t
+check_parent (x509_cert_t child, x509_cert_t parent)
+{
+  gpg_error_t err = 0;
+  char *issuer = ksba_cert_get_issuer (child->crt, 0);
+  char *subject = ksba_cert_get_subject (parent->crt, 0);
+
+  /* Parent must be the issuer */
+  if (strcmp (issuer, subject) != 0)
+    err = gpg_error (GPG_ERR_BAD_CERT_CHAIN);
+
+  if (!err)
+    debug_msg (2, "checking signature by: %s", issuer);
+
+  free (issuer);
+  free (subject);
+
+  if (!err)
+    {
+      /* FIXME: Expired? Future? */
+
+      err = _ntbtls_x509_check_cert_sig (parent->crt, child->crt);
+    }
+
+  return err;
+}
+
 
 gpg_error_t
 _ntbtls_x509_verify (x509_cert_t chain, x509_cert_t trust_ca, x509_crl_t ca_crl,
                      const char *cn, int *r_flags)
 {
-  //FIXME:
+  gpg_error_t err;
+  x509_cert_t cert, cert_prev;
+  x509_cert_t ca;
+  int flag, chainlen;
 
-  return 0;
+  *r_flags = 0;
+
+  // FIXME: with peer hostname, check it.
+  //if (cn)
+  //  {
+  //  }
+
+  cert_prev = NULL;
+  for (cert = chain; cert->next; cert_prev = cert, cert = cert->next)
+    if ((err = check_parent (cert, cert->next)))
+      return err;
+
+  if (ksba_cert_is_ca (cert->crt, &flag, &chainlen))
+    cert = cert_prev;
+
+  if (cert == NULL)
+    return gpg_error (GPG_ERR_INTERNAL);
+
+  for (ca = trust_ca; ca; ca = ca->next)
+    if (check_parent (cert, ca) == 0)
+      {
+	/* FIXME: More check/validation ? */
+	return 0;
+      }
+
+  /* No CA found.  */
+  return gpg_error (GPG_ERR_NOT_FOUND);
 }
 
 
-- 



More information about the Gnupg-devel mailing list