+bool tnl_ep_set_x509_credentials(tnl_ep_t *tnl_ep, const char *privkey, const char *certificate, const char *trust, const char *crl) {
+ int err;
+
+ if(tnl_ep->cred.certificate) {
+ gnutls_certificate_free_credentials(tnl_ep->cred.certificate);
+ tnl_ep->cred.certificate = NULL;
+ }
+
+ if((err = gnutls_certificate_allocate_credentials(&tnl_ep->cred.certificate)) < 0) {
+ logger(LOG_ERR, _("Failed to allocate certificate credentials: %s"), gnutls_strerror(err));
+ return false;
+ }
+
+ if((err = gnutls_certificate_set_x509_key_file(tnl_ep->cred.certificate, certificate, privkey, GNUTLS_X509_FMT_PEM)) < 0) {
+ logger(LOG_ERR, _("Failed to load X.509 key and/or certificate: %s"), gnutls_strerror(err));
+ return false;
+ }
+
+ tnl_ep->cred.type = GNUTLS_CRD_CERTIFICATE;
+
+ if(trust && (err = gnutls_certificate_set_x509_trust_file(tnl_ep->cred.certificate, trust, GNUTLS_X509_FMT_PEM)) < 0) {
+ logger(LOG_ERR, _("Failed to set X.509 trust file: %s"), gnutls_strerror(err));
+ return false;
+ }
+
+ if(crl && (err = gnutls_certificate_set_x509_crl_file(tnl_ep->cred.certificate, crl, GNUTLS_X509_FMT_PEM)) < 0) {
+ logger(LOG_ERR, _("Failed to set X.509 CRL file: %s"), gnutls_strerror(err));
+ return false;
+ }
+
+ //gnutls_certificate_set_verify_flags(tnl_ep->cred.certificate, GNUTLS_VERIFY_DISABLE_CA_SIGN);
+
+ return true;
+}
+
+bool tnl_ep_set_openpgp_credentials(tnl_ep_t *tnl_ep, const char *privkey, const char *pubkey, const char *keyring, const char *trustdb) {
+ int err;
+
+ if(tnl_ep->cred.certificate) {
+ gnutls_certificate_free_credentials(tnl_ep->cred.certificate);
+ tnl_ep->cred.certificate = NULL;
+ }
+
+ if((err = gnutls_certificate_allocate_credentials(&tnl_ep->cred.certificate)) < 0) {
+ logger(LOG_ERR, _("Failed to allocate certificate credentials: %s"), gnutls_strerror(err));
+ return false;
+ }
+
+ if((err = gnutls_certificate_set_openpgp_key_file(tnl_ep->cred.certificate, pubkey, privkey)) < 0) {
+ logger(LOG_ERR, _("Failed to load public and/or private OpenPGP key: %s"), gnutls_strerror(err));
+ return false;
+ }
+
+ tnl_ep->cred.type = GNUTLS_CRD_CERTIFICATE;
+
+ if(keyring && (err = gnutls_certificate_set_openpgp_keyring_file(tnl_ep->cred.certificate, keyring)) < 0) {
+ logger(LOG_ERR, _("Failed to set OpenPGP keyring file: %s"), gnutls_strerror(err));
+ return false;
+ }
+
+ if(trustdb && (err = gnutls_certificate_set_openpgp_trustdb(tnl_ep->cred.certificate, trustdb)) < 0) {
+ logger(LOG_ERR, _("Failed to set OpenPGP trustdb file: %s"), gnutls_strerror(err));
+ return false;
+ }
+
+ //gnutls_certificate_set_verify_flags(tnl_ep->cred.certificate, GNUTLS_VERIFY_DISABLE_CA_SIGN);
+
+ return true;
+}
+
+static bool tnl_authenticate_x509(tnl_t *tnl) {
+ gnutls_x509_crt cert;
+ const gnutls_datum *certs;
+ int ncerts = 0, result;
+ char name[1024];
+ int len;
+
+ certs = gnutls_certificate_get_peers(tnl->session, &ncerts);
+
+ if (!certs || !ncerts) {
+ logger(LOG_ERR, _("tnl: no certificates from %s"), tnl->remote.hostname);
+ return false;
+ }
+
+ gnutls_x509_crt_init(&cert);
+ result = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER);
+
+ if(result) {
+ logger(LOG_ERR, _("tnl: error importing certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(result));
+ gnutls_x509_crt_deinit(cert);
+ return false;
+ }
+
+ len = sizeof name;
+ result = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, name, &len);
+ gnutls_x509_crt_deinit(cert);
+
+ if(result) {
+ logger(LOG_ERR, _("tnl: could not extract common name from certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(result));
+ return false;
+ }
+
+ if(len > sizeof name) {
+ logger(LOG_ERR, _("tnl: common name from certificate from %s too long"), tnl->remote.hostname);
+ return false;
+ }
+
+ if(tnl->remote.id && strcmp(tnl->remote.id, name)) {
+ logger(LOG_ERR, _("tnl: peer %s is %s instead of %s"), tnl->remote.hostname, name, tnl->remote.id);
+ return false;
+ }
+
+ replace(tnl->remote.id, xstrdup(name));
+
+ result = gnutls_certificate_verify_peers(tnl->session);
+
+ if(result < 0) {
+ logger(LOG_ERR, "tnl: error verifying certificate from %s (%s): %s", tnl->remote.id, tnl->remote.hostname, gnutls_strerror(result));
+ return false;
+ }
+
+ if(result) {
+ logger(LOG_ERR, "tnl: certificate from %s (%s) not good, verification result %x", tnl->remote.id, tnl->remote.hostname, result);
+ return false;
+ }
+
+ return true;
+}
+
+static bool tnl_authenticate(tnl_t *tnl) {
+ switch(tnl->local.cred.type) {
+ case GNUTLS_CRD_CERTIFICATE:
+ switch(gnutls_certificate_type_get(tnl->session)) {
+ case GNUTLS_CRT_X509:
+ return tnl_authenticate_x509(tnl);
+ case GNUTLS_CRT_OPENPGP:
+ //return tnl_authenticate_openpgp(tnl);
+ default:
+ logger(LOG_ERR, "tnl: unknown certificate type for session with %s (%s)", tnl->remote.id, tnl->remote.hostname);
+ return false;
+ }
+
+ case GNUTLS_CRD_ANON:
+ logger(LOG_ERR, "tnl: anonymous authentication not yet supported");
+ return false;
+
+ case GNUTLS_CRD_SRP:
+ logger(LOG_ERR, "tnl: SRP authentication not yet supported");
+ return false;
+
+ default:
+ logger(LOG_ERR, "tnl: unknown authentication type for session with %s (%s)", tnl->remote.id, tnl->remote.hostname);
+ return false;
+ }
+}
+