2001-12-19 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgmeplug / gpgmeplug.c
index 73451d6..35c723c 100644 (file)
     \see cryptplug.h
 */
 
+#ifdef HAVE_CONFIG_H
 #include <config.h>
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
 #include <errno.h>
+#include <time.h>
 
-#include <gpgme.h>
-#include <util.h>
+#include "gpgme.h"
+#ifndef GPGMEPLUG_PROTOCOL
+#define GPGMEPLUG_PROTOCOL GPGME_PROTOCOL_OpenPGP
+#endif
 
 #include "cryptplug.h"
 
@@ -97,6 +102,30 @@ typedef struct {
 Config config;
 
 
+
+
+/*
+  temporary code!!
+
+  will be removed!!
+
+  asking for passphrase will be handeked via gpg-agent!!
+*/
+static char tmpPassphrase[1024];
+struct passphrase_cb_info_s {
+    GpgmeCtx c;
+    int did_it;
+};
+static const char *
+passphrase_cb (void *opaque, const char *desc, void *r_hd)
+{
+    return tmpPassphrase;
+}
+
+
+
+
+
 #define NEAR_EXPIRY 14
 
 bool initialize()
@@ -145,10 +174,10 @@ void deinitialize()
 {
   unsigned int i;
   for( i = 0; i < config.numDirectoryServers; ++i ) {
-    _gpgme_free( (char *)config.directoryServers[i].servername );
-    _gpgme_free( (char *)config.directoryServers[i].description );
+    free( (char *)config.directoryServers[i].servername );
+    free( (char *)config.directoryServers[i].description );
   }
-  _gpgme_free( config.directoryServers );
+  free( config.directoryServers );
 }
 
 
@@ -584,17 +613,17 @@ void appendDirectoryServer( const char* servername,
                             const char* description )
 {
   struct DirectoryServer *newServers = NULL;
-  newServers = xtryrealloc( config.directoryServers,
-                         (1+config.numDirectoryServers) * sizeof *newServers );
+  newServers = realloc( config.directoryServers,
+                       (1+config.numDirectoryServers) * sizeof *newServers );
   if( newServers ) {
     config.directoryServers = newServers;
     newServers[ config.numDirectoryServers ].servername =
-      xtrymalloc( strlen( servername ) );
+      malloc( 1+strlen( servername ) );
     if( newServers[ config.numDirectoryServers ].servername ) {
       strcpy( (char *)newServers[ config.numDirectoryServers ].servername,
         servername );
       newServers[ config.numDirectoryServers ].description =
-        xtrymalloc( strlen(  description ) );
+        malloc( 1+strlen(  description ) );
       if( newServers[ config.numDirectoryServers ].description ) {
         strcpy( (char *)newServers[ config.numDirectoryServers ].description,
           description );
@@ -610,18 +639,18 @@ void setDirectoryServers( struct DirectoryServer server[], unsigned int size )
   unsigned int i;
   int oldSize = config.numDirectoryServers;
   struct DirectoryServer *newServers = NULL;
-  newServers = xtrycalloc ( size, sizeof *newServers );
+  newServers = calloc ( size, sizeof *newServers );
   if( newServers ) {
     for( i=0; i < oldSize; ++i ) {
-      _gpgme_free( (char *)config.directoryServers[i].servername );
-      _gpgme_free( (char *)config.directoryServers[i].description );
+      free( (char *)config.directoryServers[i].servername );
+      free( (char *)config.directoryServers[i].description );
     }
-    _gpgme_free( config.directoryServers );
+    free( config.directoryServers );
     for( i=0; i < size; ++i ) {
-      newServers[ i ].servername = xtrymalloc( strlen( server[i].servername ) );
+      newServers[ i ].servername = malloc( 1+strlen( server[i].servername ) );
       if( newServers[ i ].servername ) {
         strcpy( (char *)newServers[ i ].servername, server[i].servername );
-        newServers[ i ].description = xtrymalloc( strlen( server[i].description ) );
+        newServers[ i ].description = malloc( 1+strlen( server[i].description ) );
         if( newServers[ i ].description ) {
           strcpy( (char *)newServers[ i ].description, server[i].description );
           newServers[ i ].port = server[i].port;
@@ -670,63 +699,362 @@ bool signMessage( const char*  cleartext,
                   const char*  certificate )
 {
   GpgmeCtx ctx;
-  GpgmeData data, sig;
+  GpgmeError err;
+  GpgmeData data,  sig;
+  size_t rSLen = 0;
+  char*  rSig  = 0;
+  bool   bOk   = false;
+
+
+
+/*
+  temporary code!!
+
+  will be removed!!
+
+  asking for passphrase will be handeked via gpg-agent!!
+*/
+  struct passphrase_cb_info_s info;
+
+
+
+
+
+  if( !ciphertext )
+    return false;
+
+  err = gpgme_new (&ctx);
+  gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
+
+
+
+
+
+
+/*
+  temporary code!!
+
+  will be removed!!
+
+  asking for passphrase will be handeked via gpg-agent!!
+*/
+  if (!getenv("GPG_AGENT_INFO")) {
+      info.c = ctx;
+      gpgme_set_passphrase_cb (ctx, passphrase_cb, &info);
+  }
+  strcpy( tmpPassphrase, certificate );
+
+
+
 
-  char buf[1024];
-  size_t nread;
 
-  
-  gpgme_new (&ctx);
   gpgme_set_armor (ctx, 1);
   gpgme_set_textmode (ctx, 1);
 
   gpgme_data_new_from_mem (&data, cleartext,
-                            strlen( cleartext ), 1 );
+                            1+strlen( cleartext ), 1 );
   gpgme_data_new ( &sig );
-  gpgme_op_sign (ctx, data, sig, GPGME_SIG_MODE_DETACH );
-
-  fputs ( "Content-Type: multipart/signed;\r\n"
-          "              protocol=\"application/pgp-signature\";\r\n"
-          "              boundary=\"42=.42=.42=.42\"\r\n"
-          "\r\n--42=.42=.42=.42\r\n",
-          stdout );
-
-  gpgme_data_rewind (data);
-  while ( !gpgme_data_read (data, buf, sizeof buf, &nread ) ) {
-        fwrite (buf, nread, 1, stdout );
+  err = gpgme_op_sign (ctx, data, sig, GPGME_SIG_MODE_DETACH );
+
+  if (!err) {
+    rSig  = gpgme_data_release_and_get_mem( sig,  &rSLen );
+    *ciphertext = malloc( rSLen + 1 );
+    if( *ciphertext ) {
+      if( rSLen ) {
+        bOk = true;
+        strncpy((char*)*ciphertext, rSig, rSLen );
+      }
+      ((char*)(*ciphertext))[rSLen] = '\0';
+    }
+    free( rSig );
   }
-  fputs ( "\r\n--42=.42=.42=.42\r\n"
-          "Content-Type: application/pgp-signature\r\n\r\n", stdout);
-
-  gpgme_data_rewind (sig);
-  while ( !gpgme_data_read (sig, buf, sizeof buf, &nread ) ) {
-        fwrite (buf, nread, 1, stdout );
+  else {
+    gpgme_data_release( sig );
+    *ciphertext = 0;
+    // hier fehlt eine Fehlerbehandlung, falls das
+    // Signieren schiefging
   }
-  fputs ( "\r\n--42=.42=.42=.42--\r\n", stdout );
-
+  gpgme_data_release( data );
   gpgme_release (ctx);
-  gpgme_data_release(data);
-  gpgme_data_release(sig);
 
-  return true;
-}
+  return bOk;
+}
+
+
+static const char*
+sig_status_to_string( GpgmeSigStat status )
+{
+    const char *result;
+
+    switch (status) {
+      case GPGME_SIG_STAT_NONE:
+        result = "Oops: Signature not verified";
+        break;
+      case GPGME_SIG_STAT_NOSIG:
+        result = "No signature found";
+        break;
+      case GPGME_SIG_STAT_GOOD:
+        result = "Good signature";
+        break;
+      case GPGME_SIG_STAT_BAD:
+        result = "BAD signature";
+        break;
+      case GPGME_SIG_STAT_NOKEY:
+        result = "No public key to verify the signature";
+        break;
+      case GPGME_SIG_STAT_ERROR:
+        result = "Error verifying the signature";
+        break;
+      case GPGME_SIG_STAT_DIFF:
+        result = "Different results for signatures";
+        break;
+      default:
+        result = "Error: Unknown status";
+        break;
+    }
+
+    return result;
+}
+
+
+bool checkMessageSignature( const char* ciphertext,
+                            const char* signaturetext,
+                            struct SignatureMetaData* sigmeta )
+{
+    GpgmeCtx ctx;
+    GpgmeSigStat status;
+    GpgmeData datapart, sigpart;
+    GpgmeError err;
+    GpgmeKey key;
+    time_t created;
+    int sig_idx = 0;
+    const char* statusStr;
+    const char* fpr;
+
+    gpgme_new( &ctx );
+    gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
+    gpgme_data_new_from_mem( &datapart, ciphertext,
+                             1+strlen( ciphertext ), 1 );
+    gpgme_data_new_from_mem( &sigpart, signaturetext,
+                             1+strlen( signaturetext ), 1 );
+
+    gpgme_op_verify( ctx, sigpart, datapart, &status );
+    gpgme_data_release( datapart );
+    gpgme_data_release( sigpart );
+
+    /* Provide information in the sigmeta struct */
+    /* the status string */
+    statusStr = sig_status_to_string( status );
+    sigmeta->status = malloc( strlen( statusStr ) + 1 );
+    if( sigmeta->status ) {
+        strcpy( sigmeta->status, statusStr );
+        sigmeta->status[strlen( statusStr )] = '\0';
+    } else
+        ; // nothing to do, is already 0
+
+    // Extended information for any number of signatures.
+    fpr = gpgme_get_sig_status( ctx, sig_idx, &status, &created );
+    sigmeta->extended_info = 0;
+    while( fpr != NULL ) {
+        struct tm* ctime_val;
+        const char* sig_status;
+
+        void* realloc_return = realloc( sigmeta->extended_info,
+                                        sizeof( struct SignatureMetaDataExtendedInfo ) * ( sig_idx + 1 ) );
+        if( realloc_return ) {
+            sigmeta->extended_info = realloc_return;
+            // the creation time
+            sigmeta->extended_info[sig_idx].creation_time = malloc( sizeof( struct tm ) );
+            if( sigmeta->extended_info[sig_idx].creation_time ) {
+                ctime_val = localtime( &created );
+                memcpy( sigmeta->extended_info[sig_idx].creation_time,
+                        ctime_val, sizeof( struct tm ) );
+            }
+
+            err = gpgme_get_sig_key (ctx, sig_idx, &key);
+            sig_status = sig_status_to_string( status );
+            sigmeta->extended_info[sig_idx].status_text = malloc( strlen( sig_status ) + 1 );
+            if( sigmeta->extended_info[sig_idx].status_text ) {
+                strcpy( sigmeta->extended_info[sig_idx].status_text,
+                    sig_status );
+                sigmeta->extended_info[sig_idx].status_text[strlen( sig_status )] = '\0';
+            }
+
+            sigmeta->extended_info[sig_idx].fingerprint = malloc( strlen( fpr ) + 1 );
+            if( sigmeta->extended_info[sig_idx].fingerprint ) {
+                strcpy( sigmeta->extended_info[sig_idx].fingerprint, fpr );
+                sigmeta->extended_info[sig_idx].fingerprint[strlen( fpr )] = '\0';
+            }
+        } else
+            break; // if allocation fails once, it isn't likely to
+                   // succeed the next time either
+
+        fpr = gpgme_get_sig_status (ctx, ++sig_idx, &status, &created);
+    }
+    sigmeta->extended_info_count = sig_idx;
+    sigmeta->nota_xml = gpgme_get_notation( ctx );
+    sigmeta->status_code = status;
 
-bool checkMessageSignature( const char* ciphertext, const char**
-        cleartext, struct SignatureMetaData* sigmeta ){ return true; }
+    gpgme_release( ctx );
+    return ( status == GPGME_SIG_STAT_GOOD );
+}
 
 bool storeCertificatesFromMessage(
         const char* ciphertext ){ return true; }
 
 
 bool encryptMessage( const char* cleartext,
-                     const char** ciphertext ){ return true; }
+                     const char** ciphertext,
+                     const char* addressee )
+{
+  GpgmeCtx ctx;
+  GpgmeError err;
+  GpgmeData gCiphertext, gPlaintext;
+  GpgmeRecipients rset;
+  size_t rCLen = 0;
+  char*  rCiph = 0;
+  bool   bOk   = false;
+
+  gpgme_new (&ctx);
+  gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
+
+  gpgme_set_armor (ctx, 1);
+  gpgme_set_textmode (ctx, 1);
+
+  gpgme_data_new_from_mem (&gPlaintext, cleartext,
+                            1+strlen( cleartext ), 1 );
+  err = gpgme_data_new ( &gCiphertext );
+
+  gpgme_recipients_new (&rset);
+
+
+  if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
+  {
+    gpgme_recipients_add_name_with_validity (rset, 
+      "/CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=Düsseldorf,C=DE",
+      GPGME_VALIDITY_FULL );
+    fputs( "\nGPGSMPLUG encryptMessage() using test key of Aegypten Project\n", stderr );
+  }
+  else
+  {
+    gpgme_recipients_add_name (rset, addressee);
+    fprintf( stderr, "\nGPGMEPLUG encryptMessage() using addressee %s\n", addressee );
+  }
+
+
+  err = gpgme_op_encrypt (ctx, rset, gPlaintext, gCiphertext );
+  if( err )
+    fprintf( stderr, "gpgme_op_encrypt() returned this error code:  %i\n\n", err );
+
+  gpgme_recipients_release (rset);
+  gpgme_data_release (gPlaintext);
+
+  if( !err ) {
+    rCiph = gpgme_data_release_and_get_mem( gCiphertext,  &rCLen );
+    *ciphertext = malloc( rCLen + 1 );
+    if( *ciphertext ) {
+      if( rCLen ) {
+        bOk = true;
+        strncpy((char*)*ciphertext, rCiph, rCLen );
+      }
+      ((char*)(*ciphertext))[rCLen] = 0;
+    }
+    free( rCiph );
+  }
+  else {
+    gpgme_data_release ( gCiphertext );
+    *ciphertext = 0;
+    // hier fehlt eine Fehlerbehandlung: fuer einen Recipient nur ein
+    // untrusted key (oder gar keiner) gefunden wurde, verweigert gpg
+    // das signieren.
+  }
+
+  gpgme_release (ctx);
+
+  fflush( stderr );
+
+  return bOk;
+}
+
 
 bool encryptAndSignMessage( const char* cleartext,
           const char** ciphertext, const char* certificate,
           struct SignatureMetaData* sigmeta ){ return true; }
 
-bool decryptMessage( const char* ciphertext, const
-          char** cleartext, const char* certificate ){ return true; }
+bool decryptMessage( const char* ciphertext,
+                     const char** cleartext,
+                     const char* certificate )
+{
+  GpgmeCtx ctx;
+  GpgmeError err;
+  GpgmeData gCiphertext, gPlaintext;
+  size_t rCLen = 0;
+  char*  rCiph = 0;
+  bool bOk = false;
+
+
+
+/*
+  temporary code!!
+
+  will be removed!!
+
+  asking for passphrase will be handeked via gpg-agent!!
+*/
+  struct passphrase_cb_info_s info;
+
+
+
+
+
+  if( !ciphertext )
+    return false;
+
+  err = gpgme_new (&ctx);
+  gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
+
+
+
+
+
+/*
+  temporary code!!
+
+  will be removed!!
+
+  asking for passphrase will be handeked via gpg-agent!!
+*/
+  if (!getenv("GPG_AGENT_INFO")) {
+      info.c = ctx;
+      gpgme_set_passphrase_cb (ctx, passphrase_cb, &info);
+  }
+  strcpy( tmpPassphrase, certificate );
+
+
+
+
+  gpgme_data_new_from_mem( &gCiphertext, ciphertext,
+                           1+strlen( ciphertext ), 1 );
+  gpgme_data_new( &gPlaintext );
+
+  gpgme_op_decrypt( ctx, gCiphertext, gPlaintext );
+  gpgme_data_release( gCiphertext );
+
+  rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
+
+  *cleartext = malloc( rCLen + 1 );
+  if( *cleartext ) {
+      if( rCLen ) {
+          bOk = true;
+          strncpy((char*)*cleartext, rCiph, rCLen );
+      }
+      ((char*)(*cleartext))[rCLen] = 0;
+  }
+
+  free( rCiph );
+  gpgme_release( ctx );
+  return bOk;
+}
 
 bool decryptAndCheckMessage( const char* ciphertext,
           const char** cleartext, const char* certificate,