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