Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.sys.acorn.programmer > #2733 > unrolled thread

E-Mail-fetcher for RISC OS using GnuTLS

Started byAlexander Ausserstorfer <bavariasound@chiemgau-net.de>
First post2013-05-20 09:18 +0200
Last post2013-05-24 11:38 +0100
Articles 5 — 3 participants

Back to article view | Back to comp.sys.acorn.programmer


Contents

  E-Mail-fetcher for RISC OS using GnuTLS Alexander Ausserstorfer <bavariasound@chiemgau-net.de> - 2013-05-20 09:18 +0200
    Re: E-Mail-fetcher for RISC OS using GnuTLS Streuner <utellan@yahoo.de> - 2013-05-23 08:29 +0200
      Re: E-Mail-fetcher for RISC OS using GnuTLS Chris Gransden <chrisg@care4free.net> - 2013-05-23 14:41 +0100
        Re: E-Mail-fetcher for RISC OS using GnuTLS Alexander Ausserstorfer <bavariasound@chiemgau-net.de> - 2013-05-24 10:05 +0200
          Re: E-Mail-fetcher for RISC OS using GnuTLS Chris Gransden <chrisg@care4free.net> - 2013-05-24 11:38 +0100

#2733 — E-Mail-fetcher for RISC OS using GnuTLS

FromAlexander Ausserstorfer <bavariasound@chiemgau-net.de>
Date2013-05-20 09:18 +0200
SubjectE-Mail-fetcher for RISC OS using GnuTLS
Message-ID<e903ae4e53.Alex@bavariasound.chiemgau-net.de>
Hello,

the first part is taken: The secure connection to a POP-server with
digital certificates using GnuTLS. The document of the project is in
German, though. Take a look at

http://home.chiemgau-net.de/ausserstorfer/Studium/

or directly at

http://home.chiemgau-net.de/ausserstorfer/Studium/Fetcher/GnuTLS/Arbeit(26).pdf

if you want know more the way I'm going.

The next part is to write the e-mail-fetching mechanism. The thirt part
will be cross-compiling to RISC OS then. And the fourth and last part
the implemention to WIMP.

It is just a project for me to learn...

A.

-- 
http://home.chiemgau-net.de/ausserstorfer/

[toc] | [next] | [standalone]


#2734

FromStreuner <utellan@yahoo.de>
Date2013-05-23 08:29 +0200
Message-ID<knkd0b$66a$1@geiz-ist-geil.priv.at>
In reply to#2733
Am 20.05.2013 09:18, schrieb Alexander Ausserstorfer:

> the first part is taken: The secure connection to a POP-server with
> digital certificates using GnuTLS. The document of the project is in
> German, though. Take a look at
>
> http://home.chiemgau-net.de/ausserstorfer/Studium/

Juste un question, plus. Currently I'm looking for a computer on which I 
can edit, compile and run the code native(lly) (means that it runs Unix 
/ Linux instead of Cygwin on Windows). I'm also thinking for a Rasperry 
Pi, Beagle or Pandora-board but I'm not sure about if you can do it there.

So, can somebody here try to compile and test the following code on a 
machine under Linux like the Rasperry PI, please? Or what is a good 
portable machine (laptop) with Unix / Linux?

The programme connects to a POP-Server using STARTTLS and fetchs from 
there the first e-mail (not complettely now, it is just for 
demonstrating). To make things more difficult, you must also have 
installed the required certificates for the server in .PEM-format in 
"usr/ssl/certs/E-Mail-Chain.crt".

To compile press the keys

gcc -<file name>.c -o <file name> -lgnutls

-------------------------------------------------------------------------

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>          // printf, scanf
#include <stdlib.h>         // Fehlercodes wie EXIT_FAILURE
#include <sys/socket.h>     // AF_INET, SOCK_STREAM, connect(...)
#include <netdb.h>          // struct hostent
#include <netinet/in.h>     // struct sockadd_in
#include <gnutls/gnutls.h>  // GnuTLS
#include <gnutls/x509.h>    // GnuTLS x.509-Zertifikate
#include <string.h>         // strcat(...)

#define MAX_BUF 1024        // Groesse des Zwischenspeichers
                             // fuer die verschluesselte
                             // Uebertragung
#define MAXMSG 512          // Groesse des Zwischenspeichers
                             // fuer die Klartextuebertragung
                             // fuer die vom Server
                             // uebermittelten Daten

// Folgende Datei muss die zur Ueberprüfung
// notwendigen Zertifikate (BASE64-codiert!) bereitstellen
    #define CAFILE "/usr/ssl/certs/E-Mail-Chain.crt"

struct hostent *hostinfo;   // enthaelt Zuordnung von Host-
                             // Addressen und -namen
struct sockaddr_in name;    // enthaelt Verbindungsinfor-
                             // mationen des verwendeten Sockets

// (Prototyp) Funktion ueberprueft das vom Server geschickte
// Zertifikat an Hand des Zertifikatsspeichers
    static int _verify_certificate_callback(gnutls_session_t session);

// (Prototyp) Funktion ermittelt die binaere IP-Nummer aus dem
// Hostnamen
    void IP_number(struct sockaddr_in *name, char *servername, uint16_t 
port);

main()
{
  int ret;    // Rueckgabewert Handshake
  int ii;     // Schleifenzaehler

  // Folgende Struktur nimmt die fuer eine verschluesselte
  // Sitzung notwendigen Angaben auf
     gnutls_session_t session;

  // Folgende Struktur nimmt die fuer den Client notwendigen
  // Ausweisungsangaben ("Ausweispapiere") auf:
  // hier: Benutzername und Passwort
  // (englisch: Secure Remote Password authentication)
     gnutls_srp_client_credentials_t srp_cred;

  // Folgende Struktur speichert die spaeter vom Server
  // geschickten Ausweispapiere; in diesem Fall ein digitales
  // Zertifikat:
     gnutls_certificate_credentials_t cert_cred;

  char buffer2[MAX_BUF + 1];  // Puffer fuer verschluesselte
                              // Uebertragung (empfangen)
  const char *err;            // enthaelt beim Auftritt eines
                              // Fehlers die Position in der
                              // Zeichenkette; Verwendung
                              // fuer
                              // gnutls_priority_set_direct()

  // Eingabe der benoetigten Daten
     char server[30];
     printf("Server: ");
     scanf("%s",server);

     char user[30]="";
     printf("User: ");
     scanf("%s",user);
     char USER[30]="USER ";        // Zusammenfuegen des POP-
     strcat(USER,user);            // Befehls USER username
     strcat(USER,"\r\n");          // Anfuegen von <Return>

     char *password;
     password=(char *)getpass("Password: ");  // Eingabe ohne
                                              // Bildschirm-
                                              // Ausgabe
     char PASSWORD[30]="PASS ";     // Zusammenfuegen des POP-
     strcat(PASSWORD,password);     // Befehls PASS passwort
     strcat(PASSWORD,"\r\n");       // Anfuegen von <Return>

     char buffer[MAXMSG];           // Puffer fuer Nachrichten
                                    // (empfangener Klartext)
     uint16_t port=110;             // Portnummer POP
     int sock=-1;                   // Fehlerwert fuer Socket
                                    // vordefinieren
     // size_t size;

  // IP_number() ermittelt die binaere IP-Nummer aus dem
  // Servername mittels DNS und schreibt diese in die Struktur
  // name vom Typ sockaddr_in, um sie fuer das Socket zur
  // Verfuegung zu stellen. Gleichzeitig wird die Port
  // Nummer dem Socket bereitgestellt.
     IP_number(&name, server, port);

  // Geeignetes Socket fuer Verbindung zum Server einrichten
  sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock == -1)
  {
   perror("socket");
   exit (EXIT_FAILURE);
  }

  // Mit Host verbinden
     if (connect(sock, (struct sockaddr *) &name, sizeof (struct 
sockaddr_in)) < 0)
     {
        perror ("connect");
        exit (EXIT_FAILURE);
     }

  // Servermeldung auslesen
     int amount = read(sock, buffer, MAXMSG);
     printf("%.*s", amount, buffer);

  // Fähigkeiten des Servers abrufen (STARTTLS)
     write(sock,"CAPA\r\n",6);
     amount = read(sock, buffer, MAXMSG);
     printf("%.*s", amount, buffer);

  // verschluesselten Verbindungsaufbau mit dem Befehl
  // 'STLS' starten (STARTTLS)
     write(sock,"STLS\r\n",6);
     amount = read(sock, buffer, MAXMSG);
     printf("%.*s", amount, buffer);

  // GnuTLS aktivieren
     gnutls_global_init();

// Ausweisdatenspeicher des Clients initialisieren
    gnutls_srp_allocate_client_credentials (&srp_cred);

// Ausweisdatenspeicher des Servers (Zertifikat) initialisieren
    gnutls_certificate_allocate_credentials (&cert_cred);

// Zertifikate aus Datei in Zertifikatsspeicher laden
    printf("Anzahl der verarbeiteten Zertifikate: %d\n", 
gnutls_certificate_set_x509_trust_file (cert_cred, CAFILE, 
GNUTLS_X509_FMT_PEM));

// Funktion und Speicher zur Ueberpruefung des vom Server
// geschickten Zertifikats festlegen
// Diese Funktion wird tatsaechlich erst aufgerufen, nachdem
// das Server-Zertifikat empfangen worden ist
// Aufruf erfolgt noch vor dem handshake
    gnutls_certificate_set_verify_function 
(cert_cred,_verify_certificate_callback);

// Folgende Funktion schreibt Benutzername und Passwort
// des Clients in den dafuer eingerichteten Speicher:
    gnutls_srp_set_client_credentials (srp_cred, user, password);

// Folgende Funktion legt fest, dass das System, auf welchem
// das Programm laueft, als CLIENT arbeiten soll. Es
// initialisiert die Sitzung:
    gnutls_init (&session, GNUTLS_CLIENT);

// Folgende Funktion schreibt Servername (Hostname) in die
// Struktur session:
    gnutls_session_set_ptr (session, (void *) server);

// Folgende Funktion schickt den als Hostname verwendeten
// Distinguished Name vor dem handshake an den Server,
// damit der Client das richtige Zertifikat erhaelt.
    gnutls_server_name_set (session, GNUTLS_NAME_DNS, server, 
strlen(server));

// Grundeinstellungen der zu bevorzugenden chiper suite fuer
// den handshake
    ret = gnutls_priority_set_direct (session, 
"NORMAL:+SRP:+SRP-RSA:+SRP-DSS", &err);
if (ret < 0)
   {
      if (ret == GNUTLS_E_INVALID_REQUEST)
     {
       fprintf (stderr, "Fehler an der Stelle: %s\n", err);
     }
     exit(1);
   }

// Folgende zwei Zeilen uebernehmen die Ausweisangaben von
// Client und Server in die Struktur session:
    gnutls_credentials_set (session, GNUTLS_CRD_SRP, srp_cred);
    gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, cert_cred);

// Folgende Funktion stellt die Verbindung von eingerichtetem
// Socket und der aktuellen TLS-Sitzung her:
    gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sock);

// handshake durchfuehren; an dieser Stelle erfolgt der
// verschluesselte Verbindungsaufbau
    do
       {
         ret = gnutls_handshake (session);
       } while (ret < 00 && gnutls_error_is_fatal (ret) == 0);

// handshake erfolgreich?
    if (ret < 0)
    {
     fprintf (stderr, "*** Fehler bei der verschluesselten 
Verbindungsherstellung.\n");
     gnutls_perror (ret);
     goto end;
    }
    else
    {
     printf ("Herstellung der verschluesselten Verbindung erfolgreich.\n");
}

// Verschluesseltes Senden des POP-Befehls
// USER username <Return>
    gnutls_record_send(session, USER,strlen(USER));

// Auslesen der verschluesselten Serverantwort
    ret = gnutls_record_recv(session,buffer2,MAX_BUF);
    if (gnutls_error_is_fatal (ret) != 0 || ret == 0)
    {
       if (ret == 0)
        {
       printf ("Kommunikationspartner hat die verschluesselte Verbindung 
abgebrochen.\n");
       goto end;
        }
      else
    {
      fprintf (stderr, "**** Fehler: %s\n", gnutls_strerror(ret));
      goto end;
     }
     }

     if (ret > 0)
  {
    printf ("%d Bytes empfangen: ", ret);
   for (ii = 0 ; ii < ret; ii++)
      {
       fputc (buffer2[ii], stdout);
      }
    }

// Verschluesseltes Senden des POP-Befehls
// PASS password <Return>
    gnutls_record_send(session, PASSWORD,strlen(PASSWORD));

// Auslesen der verschluesselten Serverantwort
    ret = gnutls_record_recv(session,buffer2,MAX_BUF);
     if (gnutls_error_is_fatal (ret) != 0 || ret == 0)
     {
       if (ret == 0)
       {
         printf ("Kommunikationspartner hat die verschluesselte 
Verbindung abgebrochen.\n");
         goto end;
       }
        else
       {
        fprintf (stderr, "**** Fehler: %s\n", gnutls_strerror(ret));
        goto end;
       }
     }

     if (ret > 0)
      {
        printf ("%d Bytes empfangen: ", ret);
        for (ii = 0 ; ii < ret; ii++)
       {
        fputc (buffer2[ii], stdout);
       }
      }

// Verschluesseltes Senden des POP-Befehls
// RETR 1 <Return>
// ruft 1. E-Mail vom Server ab
    gnutls_record_send(session, "RETR 1\r\n", 8);

// Auslesen der verschluesselten Serverantwort
    ret = gnutls_record_recv(session,buffer2,MAX_BUF);
     if (gnutls_error_is_fatal (ret) != 0 || ret == 0)
     {
       if (ret == 0)
         {
          printf ("Kommunikationspartner hat die verschluesselte 
Verbindung abgebrochen.\n");
          goto end;
         }
           else
         {
          fprintf (stderr, "**** Fehler: %s\n", gnutls_strerror(ret));
          goto end;
         }
      }

     if (ret > 0)
     {
       printf ("%d Bytes empfangen: ", ret);
       for (ii = 0 ; ii < ret; ii++)
      {
       fputc (buffer2[ii], stdout);
      }
    }

   // Folgende Funktion teilt dem Kommunikationspartner (hier
   // POP-Server) mit, dass und wie die Verbindung
   // abgebrochen werden soll. Damit ist der Verbindungs-
   // abbruch von einer arglistigen Unterbrechung unter-
   // scheidbar.
      gnutls_bye (session, GNUTLS_SHUT_RDWR);

   end: // Marke

   // Eingerichtetes Socket schliessen (beenden)
      close(sock);

   // Sitzungsdaten loeschen und damit Speicher freigeben
      gnutls_deinit(session);

   // Ausweisspeicher des Clients freigeben
      gnutls_srp_free_client_credentials (srp_cred);

   // Ausweisspeicher des Servers freigeben
      gnutls_certificate_free_credentials (cert_cred);

   // GnuTLS beenden und damit Speicher freigeben
      gnutls_global_deinit();

}

// IP_number(...) ermittelt die binaere IP-Adresse aus dem
// gegebenen Hostnamen und wandelt diese in eine für Menschen
// schreibbare Version um. Die ermittelte binaere IP-Adresse
// wird ausserdem in die Struktur name vom Typ sockaddr_in
// geschrieben, damit sie dem Socket zur Verfuegung steht.
// Gleichzeitig wird mit Hilfe von htons(...) die Portnummer in
// die vom System verwendete binaere Form umgewandelt,
// damit sie in die Struktur name geschrieben werden kann.

void IP_number(struct sockaddr_in *name, char *servername, uint16_t port)
{
  char serverIP[16];

  // Die Funktion
  // struct hostent * gethostbyname (const char *name)
  // ermittelt binaere IP-Nummer

     if(hostinfo=gethostbyname(servername))
     {

     // inet_ntop() wandelt _binaere IP-Nummer in die
     // fuer Menschen lesbare Nummern-Punkt-Schreibweise
     // um. (Beispiel: 193.175.141.61).

        inet_ntop(PF_INET, hostinfo->h_addr_list[0], serverIP, 16);
        printf("IP: %s\n", serverIP);

     // Im Folgenden werden Adressformat, binaere
     // Portnummer und binaere IP-Adresse in die Struktur
     // name vom Typ sockaddr_in geschrieben, damit diese
     // Angaben dem Socket zum Verbindungsaufbau zur
     // Verfuegung stehen.

        name->sin_family = PF_INET;
        name->sin_port = htons(port);
        name->sin_addr = *(struct in_addr *) hostinfo->h_addr;
     }
      else
     {
      fprintf(stderr, "Unbekannter Host %s.\n", servername);
      exit (EXIT_FAILURE);
     }
}

// Unterprogramm zur Ueberprüfung des Server-Zertifikats
    static int _verify_certificate_callback (gnutls_session_t session)
    {
        unsigned int status;
	   const gnutls_datum_t *cert_list;
	   unsigned int cert_list_size;
	   int ret;
	   gnutls_x509_crt_t cert;
	   const char *hostname;
	
	// Hostname auslesen
	   hostname = gnutls_session_get_ptr (session);
	
	// Folgende Funktion ueberprueft das vom Server geschickte Zertifikat
	// an Hand der zuvor in den Zertifizierungsspeicher der Sitzung
	// geladenen Zertifikate
	   ret = gnutls_certificate_verify_peers2 (session, &status);
	   if (ret < 0)
	     {
	       printf ("Fehler. Zertifikat konnte nicht ueberprueft werden.\n");
		   return (GNUTLS_E_CERTIFICATE_ERROR);
          }
	
	// &: bitweises UND: 1 UND 1 = 1 (sonst immer 0);
	// if (0); 0 entspricht FALSCH (FALSE), damit Bedingung nicht erfuellt.
	// Jeder andere Wert entspricht WAHR (TRUE), damit Bedingung erfuellt.
	
	   if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
	     printf ("Das Zertifikat hat keinen bekannten Aussteller.\n");
	
	   if (status & GNUTLS_CERT_REVOKED)
	     printf ("Das Zertifikat wurde widerrufen.\n");
	
	   if (status & GNUTLS_CERT_EXPIRED)
          printf ("Das Zertifikat ist abgelaufen.\n");

        if (status & GNUTLS_CERT_NOT_ACTIVATED)
          printf ("Das Zertifikat wurde bis jetzt nicht aktiviert.\n");

        if (status & GNUTLS_CERT_INVALID)
          {
            printf ("Dem Zertifikat wird nicht vertraut.\n");
            return (GNUTLS_E_CERTIFICATE_ERROR);
          }

        if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
          return (GNUTLS_E_CERTIFICATE_ERROR);

        if (gnutls_x509_crt_init (&cert) < 0 )
          {
           printf ("Initialisierungsfehler.\n");
           return (GNUTLS_E_CERTIFICATE_ERROR);
          }

     // Die vom Server geschickten Zertifikate speichern	
        cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
        if (cert_list == NULL)
          {
            printf ("Kein Zertifikat erhalten!\n");
            return (GNUTLS_E_CERTIFICATE_ERROR);
          }

	// Umwandlung des Zertifikatformats von .DER in gnutls_x509_crt_t
	// gnutls_x509_crt_t ist GnuTLS-internes Format.
        if (gnutls_x509_crt_import (cert, &cert_list[0], 
GNUTLS_X509_FMT_DER) < 0)
           {
             printf ("error parsing certificate\n");
             return (GNUTLS_E_CERTIFICATE_ERROR);
           }

         if (!gnutls_x509_crt_check_hostname (cert, hostname))
           {
             printf ("Zertifikatstraeger stimmt nicht mit Hostnamen 
ueberein. '%s'\n", hostname);
		    return (GNUTLS_E_CERTIFICATE_ERROR);
	      }
	
	gnutls_x509_crt_deinit (cert);
	
	// Normaler Programmablauf, d. h. Handshake durchfuehren.
        return (0);
}

-- 
http://home.chiemgau-net.de/ausserstorfer7

[toc] | [prev] | [next] | [standalone]


#2735

FromChris Gransden <chrisg@care4free.net>
Date2013-05-23 14:41 +0100
Message-ID<53505c8d40chrisg@care4free.net>
In reply to#2734
In article <knkd0b$66a$1@geiz-ist-geil.priv.at>,
   Streuner <utellan@yahoo.de> wrote:
> Am 20.05.2013 09:18, schrieb Alexander Ausserstorfer:

> > the first part is taken: The secure connection to a POP-server with
> > digital certificates using GnuTLS. The document of the project is in
> > German, though. Take a look at
> >
> > http://home.chiemgau-net.de/ausserstorfer/Studium/

> Juste un question, plus. Currently I'm looking for a computer on which I 
> can edit, compile and run the code native(lly) (means that it runs Unix 
> / Linux instead of Cygwin on Windows). I'm also thinking for a Rasperry 
> Pi, Beagle or Pandora-board but I'm not sure about if you can do it there.

> So, can somebody here try to compile and test the following code on a 
> machine under Linux like the Rasperry PI, please? Or what is a good 
> portable machine (laptop) with Unix / Linux?

> The programme connects to a POP-Server using STARTTLS and fetchs from 
> there the first e-mail (not complettely now, it is just for 
> demonstrating). To make things more difficult, you must also have 
> installed the required certificates for the server in .PEM-format in 
> "usr/ssl/certs/E-Mail-Chain.crt".

It builds and runs fine natively on RISC OS. Although I get the following
when I tested it with gmail,

Anzahl der verarbeiteten Zertifikate: 2
*** Fehler bei der verschluesselten Verbindungsherstellung.
GnuTLS error: A TLS packet with unexpected length was received.
*

Chris.

[toc] | [prev] | [next] | [standalone]


#2737

FromAlexander Ausserstorfer <bavariasound@chiemgau-net.de>
Date2013-05-24 10:05 +0200
Message-ID<3b9dc15053.Alex@bavariasound.chiemgau-net.de>
In reply to#2735
In message <53505c8d40chrisg@care4free.net>
          Chris Gransden <chrisg@care4free.net> wrote:

[programm code]

> It builds and runs fine natively on RISC OS.

Did you build it _natively_ on RISC OS?

> Although I get the following when I tested it with gmail,
>
> Anzahl der verarbeiteten Zertifikate: 2
> *** Fehler bei der verschluesselten Verbindungsherstellung.
> GnuTLS error: A TLS packet with unexpected length was received.

Many thanks for the hint! Will try and examine that, soon.

A.

-- 
http://home.chiemgau-net.de/ausserstorfer/

[toc] | [prev] | [next] | [standalone]


#2738

FromChris Gransden <chrisg@care4free.net>
Date2013-05-24 11:38 +0100
Message-ID<5350cfad90chrisg@care4free.net>
In reply to#2737
In article <3b9dc15053.Alex@bavariasound.chiemgau-net.de>,
   Alexander Ausserstorfer <bavariasound@chiemgau-net.de> wrote:
> In message <53505c8d40chrisg@care4free.net>
>           Chris Gransden <chrisg@care4free.net> wrote:

> [programm code]

> > It builds and runs fine natively on RISC OS.

> Did you build it _natively_ on RISC OS?

Once I got all the required library dependancies built it builds fine on
RISC OS with GCC.
Hopefully all the libraries you need will be available for download from
riscos.info in the next few days.

Chris.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.sys.acorn.programmer


csiph-web