[archimedes] Re: POP3S-Fetcher (Web8)

  • From: Alexander Ausserstorfer <bavariasound@xxxxxxxxxxxxxxx>
  • To: archimedes@xxxxxxxxxxxxx
  • Date: Sat, 10 May 2014 15:13:38 +0200

In message <b02efe0454.Alex@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>
          Alexander Ausserstorfer <bavariasound@xxxxxxxxxxxxxxx> wrote:

>>>> Das könnte unsere Messenger Pro Probleme unter SSL beim Senden erklären!
>>>> Sollte man Andrew vielleicht mal drauf ansetzen.
>>> Ich bin mir nicht sicher, ob der von mir beschriebene Effekt damit zu
>>> tun hat, weil man beim Senden das Protokoll SMTP verwendet. Mein
>>> Programm holt aber die E-Mail vom Server und verwendet hierbei das
>>> Protokoll POP3.
>>>
>>> Es kann höchstens sein, dass SMTP das gleich gestaltet wie POP3.
>>
>> Ja, CR LF . CR LF beendet DATA. DATA ist das SMTP Kommando für "jetzt
>> will ich Dir die Mail schicken".
>> http://de.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#Protokoll
>
> Ich gehe jetzt mal davon aus, dass dass bei jedem
> (Telnet)-Terminalprogramm bei einer "Multiline-Response" (mehrzeiligen
> Antwort) so funktioniert. Denn sonst könnte man sich ja nicht einfach
> mit einem Terminalprogramm in einen POP3S-Server einloggen.

Nein, ich muss diese Aussage bezüglich Telnet-Terminalprogramm leider
zurücknehmen. Zumindest hier bei mir macht jedes Programm etwas anderes.

So, wie es aussieht, habe ich jetzt den richtigen 'Algorithmus'
beisammen. Es handelt sich um folgende Zeilen des kleinen Programmchens:

 if (ret > 0)
 {
   // printf ("%d Bytes empfangen: ", ret);
   for (ii = 0 ; ii < ret; ii++)
  {
    if ((int)buffer2[ii]==13 && m==0) {m++; d=1;}
    if ((int)buffer2[ii]==10 && m==1) {m++; d=1;}
    if ((int)buffer2[ii]==13 && m==3) {m++; d=1;}
    if ((int)buffer2[ii]!=13 && m==3) {m=0;}
    if ((int)buffer2[ii]==46 && m==2) {m++; d=1;}
    if ((int)buffer2[ii]==13 && m==2) {m=1; d=1;}
    if ((int)buffer2[ii]==10 && m==4) {m=0; ret=0;}
    if (m < 3) { printf("%c",(buffer2[ii])); }
    if (d==0) m=0;
    d=0;
  }
 } while (ret!=0);

Warum das funktioniert? Ich habe ehrlich gesagt keine Ahnung. Als ich
daran herumfummelte, ging es plötzlich. Das war eine Überraschung! Ich
muss aber noch überprüfen, ob alles - Zeichen für Zeichen - passt.
Bisher sieht es aber danach aus.

Ich habe euch den Quellcode noch einmal angehängt. Wer will, kann diesen
ja zur Übung mal durch den Compiler jagen und das Programm ausprobieren.
Abrufen kann man damit bisher nur eine E-Mail nach Auswahl. Danach muss
das Programm neu gestartet werden.

Der nächste Schritt soll sein, dass automatisch alle vorhandenen E-Mails
abgerufen und auf den Schirm ausgegeben werden. Danach soll's schon in
Richtung RISC OS gehen, d. h. die E-Mails sollen dann in einzelne
Dateien geschrieben werden (zur Weiterverarbeitung durch ein gesondertes
Programm).

Wer Fehler finden sollte, bitte bei mir melden!

Ciao,

Alex'

-- 
http://home.chiemgau-net.de/ausserstorfer/
Sent wirelessly from RISC OS

#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 (mit Tunnelung, aber Daten
                                                        // im Klartext) - POP3S
#define MAXMSG 512          // Groesse des Zwischenspeichers
                            // fuer die Klartextuebertragung
                            // fuer die vom Server
                            // uebermittelten Daten (ohne Tunnelung)
                                                        // für StartTLS

// 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 für buffer2[ii]
 int jj;     // Innerer Schleifenzähler, damit restliche Zeichen ausgegeben 
werden.
 int m=0;    // Schrittzähler für <CR><LF><46><CR><LF> -> marktiert Ende einer 
E-Mail!
 int d=0;    // Merker für vorhergegangenes Zeichen

 // 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[40]="";
    printf("User: ");
    scanf("%s",user);
    char USER[50]="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=995;             // Portnummer POPS
    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("\nAnzahl 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");
}

// 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);
   }
      fputs ("\n", stdout);
   }

// 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);
   }
      fputs ("\n", stdout);
   }
   
   /*
   if (!strncmp(buffer2,"+OK",3))
      {
            printf("USER OK\n");
          }
          else
          {
            printf("USER LOGIN ERROR\n");
            goto end;
          }
        */
   
// 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);
      }
       fputs ("\n", stdout);
     }

         /*
         if (!strncmp(buffer2,"+OK",3))
      {
            printf("PASSWORT LOGIN OK\n");
          }
          else
          {
            printf("PASSWORT ERROR\n");
            goto end;
          }
     */   

// Verschluesseltes Senden des POP-Befehls
// STAT <Return>
// gibt Anzahl und Gesamtgröße aller E-Mails an
   gnutls_record_send(session, "STAT\r\n",6);

// 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);
      }
       fputs ("\n", stdout);
     }

         /*
         if (!strncmp(buffer2,"+OK",3))
      {
            printf("STAT OK\n");
          }
          else
          {
            printf("STAT ERROR\n");
            goto end;
          }
     */   
          
// Verschluesseltes Senden des POP-Befehls
// LIST <Return>
// Führt E-Mails detailiert auf
   gnutls_record_send(session, "LIST\r\n",6);

// 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);
      }
       fputs ("\n", stdout);
     }

         /*
         if (!strncmp(buffer2,"+OK",3))
      {
            printf("LIST OK\n");
          }
          else
          {
            printf("LIST ERROR\n");
            goto end;
          }
     */           
            
//E-Mail von Hand abfragen
int x=0;   // 1-te E-Mail
int k=0;   // Größe der Nachricht

printf("n-te E-Mail abfragen (laufende Nummer n):\n");
// fflush(stdin);
scanf("%d",&x);  
          
// Verschluesseltes Senden des POP-Befehls
// RETR x <Return>
// Holt E-Mails vom Server

  // int x=6;            // l-te E-Mail
  // int k=4106;         // Größe der Nachricht
  int i=0;               // Bytezähler
  char comm_retr[20];    // Kommando RETR x

  sprintf(comm_retr,"RETR %d\r\n",x);
  // printf("Kommando lautet: %s",comm_retr);
  
  gnutls_record_send(session,comm_retr, strlen(comm_retr));

  // Auslesen der verschluesselten Serverantwort
  // Holen von +OK?
       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);
         }
          fputs ("\n", stdout);
        }
   
        // Falls kein +OK zurückkommt, abbrechen
        if (strncmp(buffer2,"+OK",3)) goto end; 

     // Holen der E-Mail
            do {
             ret = gnutls_record_recv(session,buffer2,MAX_BUF);
                         // printf("\n ------------ RET-WERT = %d ------------ 
\n",ret); 
             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++)
            {
                          if ((int)buffer2[ii]==13 && m==0) {m++; d=1;}  // 
<CR> an 1. Stelle? -> Wenn ja, merken!
                          if ((int)buffer2[ii]==10 && m==1) {m++; d=1;}  // 
<LF> an 2. Stelle? -> Wenn ja, merken!
                          if ((int)buffer2[ii]==13 && m==3) {m++; d=1;}  // 
<CR> an 4. Stelle? -> Wenn ja, merken!
                          if ((int)buffer2[ii]!=13 && m==3) {m=0;}       // 
<46> an 4. Stelle? -> Wenn ja, Zähler rücksetzen!
                          if ((int)buffer2[ii]==46 && m==2) {m++; d=1;}  // 
<46> an 3. Stelle? -> Wenn ja, merken!
                          if ((int)buffer2[ii]==13 && m==2) {m=1; d=1;}  // 
<13> an 3. Stelle? -> Wenn ja, merken! Zähler auf 1. Stelle rücksetzen! 
Berücksichtigt endlose Folgen <CR><LF><CR><LF>...<CR><LF>
                          if ((int)buffer2[ii]==10 && m==4) {m=0; ret=0;} // 
<10> an 5. Stelle? -> Wenn ja, wurde die Folge <CR><LF><46><CR><LF> 
durchlaufen, und das Ende der E-Mail ist erreicht.
              if (m < 3) { printf("%c",(buffer2[ii])); } // Zeichen ausgeben; 
Zeichen nur bis <CR><LF> ausgeben.
                          if (d==0) m=0;  // erfolgloser Durchlauf
                          d=0;            // Merker rücksetzen
                        }
           }
        } while (ret!=0); 
  
  /*
  // aktuelle E-Mail löschen?
     char key[2];
     printf("Aktuelle E-Mail loeschen (j/n)?\n");
         fflush(stdout);
         scanf("%s",key);
         // printf("Eingabe war: %s\n",key);
         
         if (key[0]=='j')
         
         {

     sprintf(comm_retr,"DEL %d\r\n",x);
     // printf("Kommando lautet: %s",comm_retr);
  
     gnutls_record_send(session,comm_retr, strlen(comm_retr));

    // Auslesen der verschluesselten Serverantwort
    // Holen von +OK?
       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);
         }
          fputs ("\n", stdout);
        }
   
        // Falls kein +OK zurückkommt, abbrechen
        if (strncmp(buffer2,"+OK",3)) goto end; 
                }
  */
 
  // 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);
         }
          
        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);
      }
          
    cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
    if (cert_list == NULL)
      {
        printf ("Kein Zertifikat gefunden!\n");
        return (GNUTLS_E_CERTIFICATE_ERROR);
      }

    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);
}

Other related posts: