SILC PKCS API was changed async. Added SilcStack support.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 8 Jul 2007 17:30:24 +0000 (17:30 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 8 Jul 2007 17:30:24 +0000 (17:30 +0000)
lib/silccore/silcauth.c
lib/silccore/silcauth.h
lib/silccore/silcmessage.c
lib/silccore/silcmessage.h

index da2a502fe210c9c43e31a16c49aa464aa14abbcb..5082162e75051d35993382aaa4df794b7a947602 100644 (file)
 
 /* Authentication Payload structure */
 struct SilcAuthPayloadStruct {
+  SilcStack stack;
+  unsigned char *random_data;
+  unsigned char *auth_data;
+  SilcUInt16 auth_len;
   SilcUInt16 len;
   SilcUInt16 auth_method;
   SilcUInt16 random_len;
-  unsigned char *random_data;
-  SilcUInt16 auth_len;
-  unsigned char *auth_data;
 };
 
 /* Parses and returns Authentication Payload */
 
-SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
+SilcAuthPayload silc_auth_payload_parse(SilcStack stack,
+                                       const unsigned char *data,
                                        SilcUInt32 data_len)
 {
   SilcBufferStruct buffer;
@@ -49,21 +51,29 @@ SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
   SILC_LOG_DEBUG(("Parsing Authentication Payload"));
 
   silc_buffer_set(&buffer, (unsigned char *)data, data_len);
-  newp = silc_calloc(1, sizeof(*newp));
-  if (!newp)
+
+  if (stack)
+    stack = silc_stack_alloc(0, stack);
+
+  newp = silc_scalloc(stack, 1, sizeof(*newp));
+  if (!newp) {
+    silc_stack_free(stack);
     return NULL;
+  }
+  newp->stack = stack;
 
   /* Parse the payload */
-  ret = silc_buffer_unformat(&buffer,
-                            SILC_STR_UI_SHORT(&newp->len),
-                            SILC_STR_UI_SHORT(&newp->auth_method),
-                            SILC_STR_UI16_NSTRING_ALLOC(&newp->random_data,
-                                                        &newp->random_len),
-                            SILC_STR_UI16_NSTRING_ALLOC(&newp->auth_data,
-                                                        &newp->auth_len),
-                            SILC_STR_END);
+  ret = silc_buffer_sunformat(stack, &buffer,
+                             SILC_STR_UI_SHORT(&newp->len),
+                             SILC_STR_UI_SHORT(&newp->auth_method),
+                             SILC_STR_UI16_NSTRING_ALLOC(&newp->random_data,
+                                                         &newp->random_len),
+                             SILC_STR_UI16_NSTRING_ALLOC(&newp->auth_data,
+                                                         &newp->auth_len),
+                             SILC_STR_END);
   if (ret == -1) {
-    silc_free(newp);
+    silc_sfree(stack, newp);
+    silc_stack_free(stack);
     return NULL;
   }
 
@@ -96,7 +106,8 @@ SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
 
 /* Encodes authentication payload into buffer and returns it */
 
-SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
+SilcBuffer silc_auth_payload_encode(SilcStack stack,
+                                   SilcAuthMethod method,
                                    const unsigned char *random_data,
                                    SilcUInt16 random_len,
                                    const unsigned char *auth_data,
@@ -114,28 +125,28 @@ SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
     autf8_len = silc_utf8_encoded_len(auth_data, auth_len, 0);
     if (!autf8_len)
       return NULL;
-    autf8 = silc_calloc(autf8_len, sizeof(*autf8));
+    autf8 = silc_scalloc(stack, autf8_len, sizeof(*autf8));
     auth_len = silc_utf8_encode(auth_data, auth_len, 0, autf8, autf8_len);
     auth_data = (const unsigned char *)autf8;
   }
 
   len = 2 + 2 + 2 + random_len + 2 + auth_len;
-  buffer = silc_buffer_alloc_size(len);
+  buffer = silc_buffer_salloc_size(stack, len);
   if (!buffer) {
-    silc_free(autf8);
+    silc_sfree(stack, autf8);
     return NULL;
   }
 
-  silc_buffer_format(buffer,
-                    SILC_STR_UI_SHORT(len),
-                    SILC_STR_UI_SHORT(method),
-                    SILC_STR_UI_SHORT(random_len),
-                    SILC_STR_UI_XNSTRING(random_data, random_len),
-                    SILC_STR_UI_SHORT(auth_len),
-                    SILC_STR_UI_XNSTRING(auth_data, auth_len),
-                    SILC_STR_END);
+  silc_buffer_sformat(stack, buffer,
+                     SILC_STR_UI_SHORT(len),
+                     SILC_STR_UI_SHORT(method),
+                     SILC_STR_UI_SHORT(random_len),
+                     SILC_STR_UI_XNSTRING(random_data, random_len),
+                     SILC_STR_UI_SHORT(auth_len),
+                     SILC_STR_UI_XNSTRING(auth_data, auth_len),
+                     SILC_STR_END);
 
-  silc_free(autf8);
+  silc_sfree(stack, autf8);
   return buffer;
 }
 
@@ -144,15 +155,19 @@ SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
 void silc_auth_payload_free(SilcAuthPayload payload)
 {
   if (payload) {
+    SilcStack stack = payload->stack;
+
     if (payload->random_data) {
       memset(payload->random_data, 0, payload->random_len);
-      silc_free(payload->random_data);
+      silc_sfree(stack, payload->random_data);
     }
     if (payload->auth_data) {
       memset(payload->auth_data, 0, payload->auth_len);
-      silc_free(payload->auth_data);
+      silc_sfree(stack, payload->auth_data);
     }
-    silc_free(payload);
+
+    silc_sfree(stack, payload);
+    silc_stack_free(stack);
   }
 }
 
@@ -195,7 +210,8 @@ unsigned char *silc_auth_get_data(SilcAuthPayload payload,
    dictates. */
 
 static unsigned char *
-silc_auth_public_key_encode_data(SilcPublicKey public_key,
+silc_auth_public_key_encode_data(SilcStack stack,
+                                SilcPublicKey public_key,
                                 const unsigned char *randomdata,
                                 SilcUInt32 random_len, const void *id,
                                 SilcIdType type, SilcUInt32 *ret_len)
@@ -204,7 +220,7 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key,
   unsigned char *pk, id_data[32], *ret;
   SilcUInt32 pk_len, id_len;
 
-  pk = silc_pkcs_public_key_encode(public_key, &pk_len);
+  pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len);
   if (!pk)
     return NULL;
 
@@ -213,163 +229,223 @@ silc_auth_public_key_encode_data(SilcPublicKey public_key,
     return NULL;
   }
 
-  buf = silc_buffer_alloc_size(random_len + id_len + pk_len);
+  buf = silc_buffer_salloc_size(stack, random_len + id_len + pk_len);
   if (!buf) {
     silc_free(pk);
     return NULL;
   }
-  silc_buffer_format(buf,
-                    SILC_STR_UI_XNSTRING(randomdata, random_len),
-                    SILC_STR_UI_XNSTRING(id_data, id_len),
-                    SILC_STR_UI_XNSTRING(pk, pk_len),
-                    SILC_STR_END);
+  silc_buffer_sformat(stack, buf,
+                     SILC_STR_UI_XNSTRING(randomdata, random_len),
+                     SILC_STR_UI_XNSTRING(id_data, id_len),
+                     SILC_STR_UI_XNSTRING(pk, pk_len),
+                     SILC_STR_END);
 
   ret = silc_buffer_steal(buf, ret_len);
 
-  silc_buffer_free(buf);
-  silc_free(pk);
+  silc_buffer_sfree(stack, buf);
+  silc_sfree(stack, pk);
 
   return ret;
 }
 
+typedef struct {
+  SilcStack stack;
+  unsigned char *pubdata;
+  SilcUInt32 pubdata_len;
+  SilcAuthGenerated generated;
+  void *context;
+} *SilcAuthGenerateContext;
+
+/* Signature callback */
+
+static void
+silc_auth_public_key_auth_generate_cb(SilcBool success,
+                                     const unsigned char *signature,
+                                     SilcUInt32 signature_len,
+                                     void *context)
+{
+  SilcAuthGenerateContext a = context;
+  SilcStack stack = a->stack;
+  SilcBuffer buf;
+
+  if (!success) {
+    a->generated(NULL, context);
+    silc_sfree(stack, a->pubdata);
+    silc_sfree(stack, a);
+    silc_stack_free(stack);
+    return;
+  }
+
+  /* Encode Authentication Payload */
+  buf = silc_auth_payload_encode(stack, SILC_AUTH_PUBLIC_KEY, a->pubdata,
+                                a->pubdata_len, signature, signature_len);
+
+  a->generated(buf, context);
+
+  silc_buffer_sfree(stack, buf);
+  silc_sfree(stack, a->pubdata);
+  silc_sfree(stack, a);
+  silc_stack_free(stack);
+}
+
 /* Generates Authentication Payload with authentication data. This is used
    to do public key based authentication. This generates the random data
    and the actual authentication data. Returns NULL on error. */
 
-SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
-                                             SilcPrivateKey private_key,
-                                             SilcRng rng, SilcHash hash,
-                                             const void *id, SilcIdType type)
+SilcAsyncOperation
+silc_auth_public_key_auth_generate(SilcPublicKey public_key,
+                                  SilcPrivateKey private_key,
+                                  SilcRng rng, SilcHash hash,
+                                  const void *id, SilcIdType type,
+                                  SilcAuthGenerated generated,
+                                  void *context)
 {
-  unsigned char *randomdata;
-  SilcBuffer buf;
+  unsigned char randomdata[256];
 
-  /* Get 256 bytes of random data */
+  /* Get random data */
   if (rng)
-    randomdata = silc_rng_get_rn_data(rng, 256);
+    silc_rng_get_rn_data(rng, sizeof(randomdata), randomdata,
+                        sizeof(randomdata));
   else
-    randomdata = silc_rng_global_get_rn_data(256);
-  if (!randomdata)
-    return NULL;
-
-  buf = silc_auth_public_key_auth_generate_wpub(public_key, private_key,
-                                               randomdata, 256, hash,
-                                               id, type);
-
-  memset(randomdata, 0, 256);
-  silc_free(randomdata);
+    silc_rng_global_get_rn_data(rng, sizeof(randomdata), randomdata,
+                               sizeof(randomdata));
 
-  return buf;
+  return silc_auth_public_key_auth_generate_wpub(public_key, private_key,
+                                                randomdata, sizeof(randomdata),
+                                                hash, id, type, generated,
+                                                context);
 }
 
 /* Generates Authentication Payload with authentication data. This is used
    to do public key based authentication. This generates the random data
    and the actual authentication data. Returns NULL on error. */
 
-SilcBuffer
+SilcAsyncOperation
 silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
                                        SilcPrivateKey private_key,
                                        const unsigned char *pubdata,
                                        SilcUInt32 pubdata_len,
                                        SilcHash hash,
-                                       const void *id, SilcIdType type)
+                                       const void *id, SilcIdType type,
+                                       SilcAuthGenerated generated,
+                                       void *context)
 {
-  unsigned char auth_data[2048 + 1];
-  SilcUInt32 auth_len;
+  SilcAuthGenerateContext a;
+  SilcAsyncOperation op;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
-  SilcBuffer buf;
+  SilcStack stack;
 
   SILC_LOG_DEBUG(("Generating Authentication Payload with data"));
 
+  /* We use the Crypto Toolkit's stack since we're doing crypto */
+  stack = silc_stack_alloc(2048, silc_crypto_stack());
+
+  a = silc_scalloc(stack, 1, sizeof(*a));
+  if (!a) {
+    generated(NULL, context);
+    return NULL;
+  }
+  a->stack = stack;
+
   /* Encode the auth data */
-  tmp = silc_auth_public_key_encode_data(public_key, pubdata, pubdata_len, id,
-                                        type, &tmp_len);
-  if (!tmp)
+  tmp = silc_auth_public_key_encode_data(stack, public_key, pubdata,
+                                        pubdata_len, id, type, &tmp_len);
+  if (!tmp) {
+    silc_sfree(stack, a);
+    silc_stack_free(stack);
+    generated(NULL, context);
     return NULL;
+  }
 
-  /* Compute the hash and the signature. */
-  if (!silc_pkcs_sign(private_key, tmp, tmp_len, auth_data,
-                     sizeof(auth_data) - 1, &auth_len, TRUE, hash)) {
+  a->pubdata = silc_smemdup(stack, pubdata, pubdata_len);
+  if (!a->pubdata) {
     memset(tmp, 0, tmp_len);
-    silc_free(tmp);
+    silc_sfree(stack, tmp);
+    silc_sfree(stack, a);
+    silc_stack_free(stack);
+    generated(NULL, context);
     return NULL;
   }
 
-  /* Encode Authentication Payload */
-  buf = silc_auth_payload_encode(SILC_AUTH_PUBLIC_KEY, pubdata, pubdata_len,
-                                auth_data, auth_len);
+  /* Compute the hash and the signature. */
+  op = silc_pkcs_sign(private_key, tmp, tmp_len, TRUE, hash,
+                     silc_auth_public_key_auth_generate_cb, a);
 
   memset(tmp, 0, tmp_len);
-  memset(auth_data, 0, sizeof(auth_data));
-  silc_free(tmp);
+  silc_sfree(stack, tmp);
 
-  return buf;
+  return op;
 }
 
-/* Verifies the authentication data. Returns TRUE if authentication was
-   successful. */
+/* Verifies the authentication data. */
 
-SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
-                                         SilcPublicKey public_key,
-                                         SilcHash hash,
-                                         const void *id, SilcIdType type)
+SilcAsyncOperation
+silc_auth_public_key_auth_verify(SilcAuthPayload payload,
+                                SilcPublicKey public_key,
+                                SilcHash hash,
+                                const void *id,
+                                SilcIdType type,
+                                SilcAuthResultCb result,
+                                void *context)
 {
+  SilcAsyncOperation op;
   unsigned char *tmp;
   SilcUInt32 tmp_len;
 
   SILC_LOG_DEBUG(("Verifying authentication data"));
 
   /* Encode auth data */
-  tmp = silc_auth_public_key_encode_data(public_key, payload->random_data,
+  tmp = silc_auth_public_key_encode_data(payload->stack,
+                                        public_key, payload->random_data,
                                         payload->random_len,
                                         id, type, &tmp_len);
   if (!tmp) {
     SILC_LOG_DEBUG(("Authentication failed"));
-    return FALSE;
+    result(FALSE, context);
+    return NULL;
   }
 
   /* Verify the authentication data */
-  if (!silc_pkcs_verify(public_key, payload->auth_data,
-                       payload->auth_len, tmp, tmp_len, hash)) {
-
-    memset(tmp, 0, tmp_len);
-    silc_free(tmp);
-    SILC_LOG_DEBUG(("Authentication failed"));
-    return FALSE;
-  }
+  op = silc_pkcs_verify(public_key, payload->auth_data,
+                       payload->auth_len, tmp, tmp_len, hash,
+                       result, context);
 
   memset(tmp, 0, tmp_len);
-  silc_free(tmp);
+  silc_sfree(payload->stack, tmp);
 
-  SILC_LOG_DEBUG(("Authentication successful"));
-
-  return TRUE;
+  return op;
 }
 
 /* Same as above but the payload is not parsed yet. This will parse it. */
 
-SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
-                                              SilcUInt32 payload_len,
-                                              SilcPublicKey public_key,
-                                              SilcHash hash,
-                                              const void *id, SilcIdType type)
+SilcAsyncOperation
+silc_auth_public_key_auth_verify_data(const unsigned char *payload,
+                                     SilcUInt32 payload_len,
+                                     SilcPublicKey public_key,
+                                     SilcHash hash,
+                                     const void *id,
+                                     SilcIdType type,
+                                     SilcAuthResultCb result,
+                                     void *context)
 {
+  SilcAsyncOperation op;
   SilcAuthPayload auth_payload;
-  int ret;
 
-  auth_payload = silc_auth_payload_parse(payload, payload_len);
+  auth_payload = silc_auth_payload_parse(silc_crypto_stack(), payload,
+                                        payload_len);
   if (!auth_payload) {
     SILC_LOG_DEBUG(("Authentication failed"));
-    return FALSE;
+    result(FALSE, context);
+    return NULL;
   }
 
-  ret = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
-                                        id, type);
+  op = silc_auth_public_key_auth_verify(auth_payload, public_key, hash,
+                                       id, type, result, context);
 
   silc_auth_payload_free(auth_payload);
 
-  return ret;
+  return op;
 }
 
 /* Verifies the authentication data directly from the Authentication
@@ -379,20 +455,25 @@ SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
    authentication then the `auth_data' is the SilcPublicKey and the
    `auth_data_len' is ignored. */
 
-SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
-                         const void *auth_data, SilcUInt32 auth_data_len,
-                         SilcHash hash, const void *id, SilcIdType type)
+SilcAsyncOperation
+silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
+                const void *auth_data, SilcUInt32 auth_data_len,
+                SilcHash hash, const void *id, SilcIdType type,
+                SilcAuthResultCb result, void *context)
 {
   SILC_LOG_DEBUG(("Verifying authentication"));
 
-  if (!payload || auth_method != payload->auth_method)
-    return FALSE;
+  if (!payload || auth_method != payload->auth_method) {
+    result(FALSE, context);
+    return NULL;
+  }
 
   switch (payload->auth_method) {
   case SILC_AUTH_NONE:
     /* No authentication */
     SILC_LOG_DEBUG(("No authentication required"));
-    return TRUE;
+    result(TRUE, context);
+    return NULL;
 
   case SILC_AUTH_PASSWORD:
     /* Passphrase based authentication. The `pkcs', `hash', `id' and `type'
@@ -405,14 +486,15 @@ SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
 
     if (!memcmp(payload->auth_data, auth_data, auth_data_len)) {
       SILC_LOG_DEBUG(("Passphrase Authentication successful"));
-      return TRUE;
+      result(TRUE, context);
+      return NULL;
     }
     break;
 
   case SILC_AUTH_PUBLIC_KEY:
     /* Public key based authentication */
     return silc_auth_public_key_auth_verify(payload, (SilcPublicKey)auth_data,
-                                           hash, id, type);
+                                           hash, id, type, result, context);
     break;
 
   default:
@@ -420,32 +502,38 @@ SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
   }
 
   SILC_LOG_DEBUG(("Authentication failed"));
+  result(FALSE, context);
 
-  return FALSE;
+  return NULL;
 }
 
 /* Same as above but parses the authentication payload before verify. */
 
-SilcBool silc_auth_verify_data(const unsigned char *payload,
-                              SilcUInt32 payload_len,
-                              SilcAuthMethod auth_method,
-                              const void *auth_data,
-                              SilcUInt32 auth_data_len, SilcHash hash,
-                              const void *id, SilcIdType type)
+SilcAsyncOperation
+silc_auth_verify_data(const unsigned char *payload,
+                     SilcUInt32 payload_len,
+                     SilcAuthMethod auth_method,
+                     const void *auth_data,
+                     SilcUInt32 auth_data_len, SilcHash hash,
+                     const void *id, SilcIdType type,
+                     SilcAuthResultCb result, void *context)
 {
+  SilcAsyncOperation op;
   SilcAuthPayload auth_payload;
-  SilcBool ret;
 
-  auth_payload = silc_auth_payload_parse(payload, payload_len);
-  if (!auth_payload || (auth_payload->auth_len == 0))
-    return FALSE;
+  auth_payload = silc_auth_payload_parse(silc_crypto_stack(), payload,
+                                        payload_len);
+  if (!auth_payload || (auth_payload->auth_len == 0)) {
+    result(FALSE, context);
+    return NULL;
+  }
 
-  ret = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
-                        hash, id, type);
+  op = silc_auth_verify(auth_payload, auth_method, auth_data, auth_data_len,
+                        hash, id, type, result, context);
 
   silc_auth_payload_free(auth_payload);
 
-  return ret;
+  return op;
 }
 
 /******************************************************************************
index 39b7c328631e42c27342e3362f745b35a2c31491..438c461cee75650958d8b82c2129ef73ea9072bc 100644 (file)
@@ -97,23 +97,27 @@ typedef struct SilcAuthPayloadStruct *SilcAuthPayload;
  *
  * SYNOPSIS
  *
- *    SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
+ *    SilcAuthPayload silc_auth_payload_parse(SilcStack stack,
+ *                                            const unsigned char *data,
  *                                            SilcUInt32 data_len);
  *
  * DESCRIPTION
  *
  *    Parses and returns Authentication Payload.  The `data' and the
- *    `data_len' are the raw payload buffer.
+ *    `data_len' are the raw payload buffer.  If `stack' is non-NULL the
+ *    memory is allcoated from `stack'.
  *
  ***/
-SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
+SilcAuthPayload silc_auth_payload_parse(SilcStack stack,
+                                       const unsigned char *data,
                                        SilcUInt32 data_len);
 
 /****f* silccore/SilcAuthAPI/silc_auth_payload_encode
  *
  * SYNOPSIS
  *
- *    SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
+ *    SilcBuffer silc_auth_payload_encode(SilcStack stack,
+ *                                        SilcAuthMethod method,
  *                                        const unsigned char *random_data,
  *                                        SilcUInt16 random_len,
  *                                        const unsigned char *auth_data,
@@ -128,8 +132,13 @@ SilcAuthPayload silc_auth_payload_parse(const unsigned char *data,
  *    argument SHOULD be UTF-8 encoded, if not library will attempt to
  *    encode it.
  *
+ *    If `stack' is non-NULL the returned buffer is allocated from `stack'.
+ *    This call consumes the `stack' so caller should push the stack before
+ *    calling this function and then later pop it.
+ *
  ***/
-SilcBuffer silc_auth_payload_encode(SilcAuthMethod method,
+SilcBuffer silc_auth_payload_encode(SilcStack stack,
+                                   SilcAuthMethod method,
                                    const unsigned char *random_data,
                                    SilcUInt16 random_len,
                                    const unsigned char *auth_data,
@@ -194,23 +203,41 @@ unsigned char *silc_auth_get_public_data(SilcAuthPayload payload,
 unsigned char *silc_auth_get_data(SilcAuthPayload payload,
                                  SilcUInt32 *auth_len);
 
+/****f* silccore/SilcAuthAPI/SilcAuthGenerated
+ *
+ * SYNOPSIS
+ *
+ *    typedef void (*SilcAuthGenerated)(const SilcBuffer data, void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Callback of this type is given as argument to
+ *    silc_auth_public_key_auth_generate and
+ *    silc_auth_public_key_auth_generate_wpub to deliver the generated
+ *    Authentication Payload.  If `data' is NULL the generating failed.
+ *
+ ***/
+typedef void (*SilcAuthGenerated)(const SilcBuffer data, void *context);
+
 /****f* silccore/SilcAuthAPI/silc_auth_public_key_auth_generate
  *
  * SYNOPSIS
  *
- *    SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
- *                                                  SilcPrivateKey private_key,
- *                                                  SilcRng rng,
- *                                                  SilcHash hash,
- *                                                  const void *id,
- *                                                  SilcIdType type);
+ *    SilcAsyncOperation
+ *    silc_auth_public_key_auth_generate(SilcPublicKey public_key,
+ *                                       SilcPrivateKey private_key,
+ *                                       SilcRng rng,
+ *                                       SilcHash hash,
+ *                                       const void *id,
+ *                                       SilcIdType type,
+ *                                       SilcAuthGenerated generated,
+ *                                       void *context);
  *
  * DESCRIPTION
  *
  *    Generates Authentication Payload with authentication data. This is used
  *    to do public key based authentication. This generates the random data
- *    and the actual authentication data. Returns NULL on error and the
- *    encoded Authentication Payload on success.
+ *    and the actual authentication data.
  *
  *    The `private_key' is used to sign the payload.  The `public_key', the
  *    and the `id' is encoded in the payload and signed.  If the `rng' is
@@ -218,24 +245,32 @@ unsigned char *silc_auth_get_data(SilcAuthPayload payload,
  *    random number generator.  Also random number is encoded in the
  *    payload before signing it with `private_key'.
  *
+ *    The `generated' is called to deliver the generated Authentication
+ *    Payload.
+ *
  ***/
-SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
-                                             SilcPrivateKey private_key,
-                                             SilcRng rng, SilcHash hash,
-                                             const void *id, SilcIdType type);
+SilcAsyncOperation
+silc_auth_public_key_auth_generate(SilcPublicKey public_key,
+                                  SilcPrivateKey private_key,
+                                  SilcRng rng, SilcHash hash,
+                                  const void *id, SilcIdType type,
+                                  SilcAuthGenerated generated,
+                                  void *context);
 
 /****f* silccore/SilcAuthAPI/silc_auth_public_key_auth_generate_wpub
  *
  * SYNOPSIS
  *
- *    SilcBuffer
+ *    SilcAsyncOperation
  *    silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
  *                                            SilcPrivateKey private_key,
  *                                            const unsigned char *pubdata,
  *                                            SilcUInt32 pubdata_len,
  *                                            SilcHash hash,
  *                                            const void *id,
- *                                            SilcIdType type);
+ *                                            SilcIdType type,
+ *                                            SilcAuthGenerated generated,
+ *                                            void *context);
  *
  * DESCRIPTION
  *
@@ -244,69 +279,108 @@ SilcBuffer silc_auth_public_key_auth_generate(SilcPublicKey public_key,
  *    the public data must be something else than purely random or its
  *    structure mut be set before signing.
  *
+ *    The `generated' is called to deliver the generated Authentication
+ *    Payload.
+ *
  ***/
-SilcBuffer
+SilcAsyncOperation
 silc_auth_public_key_auth_generate_wpub(SilcPublicKey public_key,
                                        SilcPrivateKey private_key,
                                        const unsigned char *pubdata,
                                        SilcUInt32 pubdata_len,
                                        SilcHash hash,
-                                       const void *id, SilcIdType type);
+                                       const void *id, SilcIdType type,
+                                       SilcAuthGenerated generated,
+                                       void *context);
+
+/****f* silccore/SilcAuthAPI/SilcAuthResult
+ *
+ * SYNOPSIS
+ *
+ *    typedef void (*SilcAuthResult)(SilcBool success, void *context);
+ *
+ * DESCRIPTION
+ *
+ *    Callback of this type is given as argument to silc_auth_verify,
+ *    silc_auth_verify_data, silc_auth_public_key_auth_verify and
+ *    silc_auth_public_key_auth_verify_data to deliver the result of
+ *    the authentication verification.  If `success' is FALSE the
+ *    authentication failed.
+ *
+ ***/
+typedef void (*SilcAuthResultCb)(SilcBool success, void *context);
 
 /****f* silccore/SilcAuthAPI/silc_auth_public_key_auth_verify
  *
  * SYNOPSIS
  *
- *    SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
- *                                          SilcPublicKey public_key,
- *                                          SilcHash hash,
- *                                          const void *id, SilcIdType type);
+ *    SilcAsyncOperation
+ *   silc_auth_public_key_auth_verify(SilcAuthPayload payload,
+ *                                    SilcPublicKey public_key,
+ *                                    SilcHash hash,
+ *                                    const void *id,
+ *                                    SilcIdType type,
+ *                                    SilcAuthResult result,
+ *                                    void *context);
  *
  * DESCRIPTION
  *
- *    Verifies the authentication data. Returns TRUE if authentication was
- *    successful.
+ *    Verifies the authentication data.  Calls the `result' to deliver
+ *    the result of the verification.
  *
  ***/
-SilcBool silc_auth_public_key_auth_verify(SilcAuthPayload payload,
-                                         SilcPublicKey public_key,
-                                         SilcHash hash,
-                                         const void *id,
-                                         SilcIdType type);
+SilcAsyncOperation
+silc_auth_public_key_auth_verify(SilcAuthPayload payload,
+                                SilcPublicKey public_key,
+                                SilcHash hash,
+                                const void *id,
+                                SilcIdType type,
+                                SilcAuthResultCb result,
+                                void *context);
 
 /****f* silccore/SilcAuthAPI/silc_auth_public_key_auth_verify_data
  *
  * SYNOPSIS
  *
- *    SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
- *                                               SilcUInt32 payload_len,
- *                                               SilcPublicKey public_key,
- *                                               SilcHash hash,
- *                                               const void *id,
- *                                               SilcIdType type);
+ *    SilcAsyncOperation
+ *    silc_auth_public_key_auth_verify_data(const unsigned char *payload,
+ *                                          SilcUInt32 payload_len,
+ *                                          SilcPublicKey public_key,
+ *                                          SilcHash hash,
+ *                                          const void *id,
+ *                                          SilcIdType type,
+ *                                          SilcAuthResult result,
+ *                                          void *context);
  *
  * DESCRIPTION
  *
  *    Same as silc_auth_public_key_auth_verify but the payload has not
- *    been parsed yet.  This will parse it.  Returns TRUE if authentication
- *    was successful.
+ *    been parsed yet.  This will parse it.  Calls the `result' to deliver
+ *    the result of the verification.
  *
  ***/
-SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
-                                              SilcUInt32 payload_len,
-                                              SilcPublicKey public_key,
-                                              SilcHash hash,
-                                              const void *id,
-                                              SilcIdType type);
+SilcAsyncOperation
+silc_auth_public_key_auth_verify_data(const unsigned char *payload,
+                                     SilcUInt32 payload_len,
+                                     SilcPublicKey public_key,
+                                     SilcHash hash,
+                                     const void *id,
+                                     SilcIdType type,
+                                     SilcAuthResultCb result,
+                                     void *context);
 
 /****f* silccore/SilcAuthAPI/silc_auth_verify
  *
  * SYNOPSIS
  *
- *    SilcBool silc_auth_verify(SilcAuthPayload payload,
- *                          SilcAuthMethod auth_method,
- *                          const void *auth_data, SilcUInt32 auth_data_len,
- *                          SilcHash hash, const void *id, SilcIdType type);
+ *    SilcAsyncOperation
+ *    silc_auth_verify(SilcAuthPayload payload,
+ *                     SilcAuthMethod auth_method,
+ *                     const void *auth_data,
+ *                     SilcUInt32 auth_data_len,
+ *                     SilcHash hash,
+ *                     const void *id, SilcIdType type,
+ *                     SilcAuthResult result, void *context);
  *
  * DESCRIPTION
  *
@@ -316,22 +390,27 @@ SilcBool silc_auth_public_key_auth_verify_data(const unsigned char *payload,
  *    are the passphrase and its length.  The passphrase MUST be UTF-8
  *    encoded.  If the method is public key authentication then the
  *    `auth_data' is the SilcPublicKey and the `auth_data_len' is ignored.
+ *    Calls the `result' to deliver the result of the verification.
  *
  ***/
-SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
-                         const void *auth_data, SilcUInt32 auth_data_len,
-                         SilcHash hash, const void *id, SilcIdType type);
+SilcAsyncOperation
+silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
+                const void *auth_data, SilcUInt32 auth_data_len,
+                SilcHash hash, const void *id, SilcIdType type,
+                SilcAuthResultCb result, void *context);
 
 /****f* silccore/SilcAuthAPI/silc_auth_verify_data
  *
  * SYNOPSIS
  *
- *    SilcBool silc_auth_verify_data(const unsigned char *payload,
- *                               SilcUInt32 payload_len,
- *                               SilcAuthMethod auth_method,
- *                               const void *auth_data,
- *                               SilcUInt32 auth_data_len, SilcHash hash,
- *                               const void *id, SilcIdType type);
+ *    SilcAsyncOperation
+ *    silc_auth_verify_data(const unsigned char *payload,
+ *                          SilcUInt32 payload_len,
+ *                          SilcAuthMethod auth_method,
+ *                          const void *auth_data,
+ *                          SilcUInt32 auth_data_len, SilcHash hash,
+ *                          const void *id, SilcIdType type,
+ *                          SilcAuthResult result, void *context);
  *
  * DESCRIPTION
  *
@@ -342,14 +421,17 @@ SilcBool silc_auth_verify(SilcAuthPayload payload, SilcAuthMethod auth_method,
  *    are the passphrase and its length.  The passphrase MUST be UTF-8
  *    encoded.  If the method is public key authentication then the
  *    `auth_data' is the SilcPublicKey and the `auth_data_len' is ignored.
+ *    Calls the `result' to deliver the result of the verification.
  *
  ***/
-SilcBool silc_auth_verify_data(const unsigned char *payload,
-                              SilcUInt32 payload_len,
-                              SilcAuthMethod auth_method,
-                              const void *auth_data,
-                              SilcUInt32 auth_data_len, SilcHash hash,
-                              const void *id, SilcIdType type);
+SilcAsyncOperation
+silc_auth_verify_data(const unsigned char *payload,
+                     SilcUInt32 payload_len,
+                     SilcAuthMethod auth_method,
+                     const void *auth_data,
+                     SilcUInt32 auth_data_len, SilcHash hash,
+                     const void *id, SilcIdType type,
+                     SilcAuthResultCb result, void *context);
 
 /****s* silccore/SilcAuthAPI/SilcKeyAgreementPayload
  *
index d69ba7fd3c67e11ab11256e613a9cd3fd4f466a1..9f53d87eeef7ddd70a41906143daa3eefc30fa1b 100644 (file)
 
 /* Payload encoding context */
 typedef struct {
+  SilcBuffer buffer;
+  SilcBuffer sign;
+  SilcStack stack;
+  SilcMessagePayloadEncoded encoded;
+  void *context;
   SilcMessageFlags flags;
   SilcPublicKey public_key;
   SilcPrivateKey private_key;
@@ -43,14 +48,32 @@ typedef struct {
   SilcCipher cipher;
   SilcHmac hmac;
   unsigned char *iv;
+  unsigned char *pk;
+  SilcUInt16 pk_len;
+  SilcUInt16 iv_len;
   SilcUInt16 payload_len;
-  SilcID *sid;
-  SilcID *rid;
+  SilcID sid;
+  SilcID rid;
 } SilcMessageEncode;
 
 
 /************************* Static utility functions *************************/
 
+static void
+silc_message_payload_encode_final(SilcBuffer buffer,
+                                 SilcMessageFlags flags,
+                                 SilcCipher cipher,
+                                 SilcHmac hmac,
+                                 unsigned char *iv,
+                                 SilcUInt32 iv_len,
+                                 SilcUInt32 payload_len,
+                                 SilcID *sender_id,
+                                 SilcID *receiver_id,
+                                 SilcStack stack,
+                                 SilcBuffer signature,
+                                 SilcMessagePayloadEncoded encoded,
+                                 void *context);
+
 /* Returns the data length that fits to the packet.  If data length is too
    big it will be truncated to fit to the payload. */
 
@@ -140,126 +163,182 @@ silc_message_signed_payload_parse(const unsigned char *data,
 /* Encodes the data to be signed to SILC_MESSAGE_FLAG_SIGNED Payload */
 
 static SilcBuffer
-silc_message_signed_encode_data(const unsigned char *message_payload,
+silc_message_signed_encode_data(SilcStack stack,
+                               const unsigned char *message_payload,
                                SilcUInt32 message_payload_len,
                                unsigned char *pk,
                                SilcUInt32 pk_len, SilcUInt32 pk_type)
 {
   SilcBuffer sign;
 
-  sign = silc_buffer_alloc_size(message_payload_len + 4 + pk_len);
+  sign = silc_buffer_salloc_size(stack, message_payload_len + 4 + pk_len);
   if (!sign)
     return NULL;
 
-  silc_buffer_format(sign,
-                    SILC_STR_UI_XNSTRING(message_payload,
-                                         message_payload_len),
-                    SILC_STR_UI_SHORT(pk_len),
-                    SILC_STR_UI_SHORT(pk_type),
-                    SILC_STR_END);
+  silc_buffer_sformat(stack, sign,
+                     SILC_STR_DATA(message_payload, message_payload_len),
+                     SILC_STR_UI_SHORT(pk_len),
+                     SILC_STR_UI_SHORT(pk_type),
+                     SILC_STR_END);
 
   if (pk && pk_len) {
     silc_buffer_pull(sign, message_payload_len + 4);
-    silc_buffer_format(sign,
-                      SILC_STR_UI_XNSTRING(pk, pk_len),
-                      SILC_STR_END);
+    silc_buffer_sformat(stack, sign,
+                       SILC_STR_UI_XNSTRING(pk, pk_len),
+                       SILC_STR_END);
     silc_buffer_push(sign, message_payload_len + 4);
   }
 
   return sign;
 }
 
+/* Signature callback */
+
+void silc_message_signed_payload_encode_cb(SilcBool success,
+                                          const unsigned char *signature,
+                                          SilcUInt32 signature_len,
+                                          void *context)
+{
+  SilcMessageEncode *e = context;
+  SilcPKCSType pk_type;
+  SilcStack stack = e->stack;
+  SilcBuffer buffer, payload;
+  SilcMessageFlags flags;
+  SilcCipher cipher;
+  SilcHmac hmac;
+  unsigned char *iv;
+  SilcUInt32 iv_len, payload_len;
+  SilcID *sid, *rid;
+  SilcMessagePayloadEncoded encoded;
+  void *encoded_context;
+
+  if (!success) {
+    e->encoded(NULL, e->context);
+    silc_buffer_sfree(stack, e->sign);
+    silc_sfree(stack, e->pk);
+    silc_sfree(stack, e);
+    silc_stack_free(stack);
+    return;
+  }
+
+  pk_type = silc_pkcs_get_type(e->private_key);
+
+  /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
+  buffer = silc_buffer_salloc_size(stack, 4 + e->pk_len + 2 + signature_len);
+  if (!buffer) {
+    e->encoded(NULL, e->context);
+    silc_buffer_sfree(stack, e->sign);
+    silc_sfree(stack, e->pk);
+    silc_sfree(stack, e);
+    silc_stack_free(stack);
+    return;
+  }
+
+  silc_buffer_sformat(stack, buffer,
+                     SILC_STR_UI_SHORT(e->pk_len),
+                     SILC_STR_UI_SHORT(pk_type),
+                     SILC_STR_END);
+
+  if (e->pk_len && e->pk) {
+    silc_buffer_pull(buffer, 4);
+    silc_buffer_sformat(stack, buffer,
+                       SILC_STR_DATA(e->pk, e->pk_len),
+                       SILC_STR_END);
+    silc_buffer_push(buffer, 4);
+  }
+
+  silc_buffer_pull(buffer, 4 + e->pk_len);
+  silc_buffer_sformat(stack, buffer,
+                     SILC_STR_UI_SHORT(signature_len),
+                     SILC_STR_DATA(signature, signature_len),
+                     SILC_STR_END);
+  silc_buffer_push(buffer, 4 + e->pk_len);
+
+  SILC_LOG_HEXDUMP(("SIG payload"), buffer->data, silc_buffer_len(buffer));
+
+  payload = e->buffer;
+  flags = e->flags;
+  cipher = e->cipher;
+  hmac = e->hmac;
+  iv = e->iv;
+  iv_len = e->iv_len;
+  payload_len = e->payload_len;
+  sid = &e->sid;
+  rid = &e->rid;
+  encoded = e->encoded;
+  encoded_context = e->context;
+
+  silc_sfree(stack, e->pk);
+  silc_buffer_sfree(stack, e->sign);
+  silc_sfree(stack, e);
+
+  /* Finalize message payload encoding */
+  silc_message_payload_encode_final(payload, flags, cipher, hmac,
+                                   iv, iv_len, payload_len,
+                                   sid, rid, stack, buffer,
+                                   encoded, encoded_context);
+}
+
 /* Encodes the SILC_MESSAGE_FLAG_SIGNED Payload and computes the digital
    signature. */
 
-static SilcBuffer
-silc_message_signed_payload_encode(const unsigned char *message_payload,
-                                  SilcUInt32 message_payload_len,
-                                  SilcPublicKey public_key,
-                                  SilcPrivateKey private_key,
-                                  SilcHash hash)
+static SilcAsyncOperation
+silc_message_signed_payload_encode(SilcBuffer payload,
+                                  SilcMessageEncode *e)
 {
-  SilcBuffer buffer, sign;
-  unsigned char auth_data[2048 + 1];
-  SilcUInt32 auth_len;
+  SilcAsyncOperation op;
+  SilcBuffer sign;
   unsigned char *pk = NULL;
   SilcUInt32 pk_len = 0;
   SilcUInt16 pk_type;
-
-  if (!message_payload || !message_payload_len || !private_key || !hash)
+  SilcStack stack = e->stack;
+  SilcHash hash = e->hash;
+  SilcPublicKey public_key = e->public_key;
+  SilcPrivateKey private_key = e->private_key;
+  unsigned char *message_payload;
+  SilcUInt16 message_payload_len;
+
+  message_payload = payload->head;
+  message_payload_len = silc_buffer_headlen(payload);
+
+  if (!message_payload || !message_payload_len || !private_key || !hash) {
+    e->encoded(NULL, e->context);
+    silc_sfree(stack, e);
+    silc_stack_free(stack);
     return NULL;
+  }
 
   if (public_key) {
-    pk = silc_pkcs_public_key_encode(public_key, &pk_len);
-    if (!pk)
+    e->pk = pk = silc_pkcs_public_key_encode(stack, public_key, &pk_len);
+    if (!pk) {
+      e->encoded(NULL, e->context);
+      silc_sfree(stack, e);
+      silc_stack_free(stack);
       return NULL;
+    }
+    e->pk_len = pk_len;
   }
   pk_type = silc_pkcs_get_type(private_key);
 
   /* Encode the data to be signed */
-  sign = silc_message_signed_encode_data(message_payload,
-                                        message_payload_len,
-                                        pk, pk_len, pk_type);
+  e->sign = sign = silc_message_signed_encode_data(stack, message_payload,
+                                                  message_payload_len,
+                                                  pk, pk_len, pk_type);
   if (!sign) {
-    silc_free(pk);
-    return NULL;
-  }
-
-  /* Sign the buffer */
-
-  /* Compute the hash and the signature. */
-  if (!silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign),
-                     auth_data, sizeof(auth_data) - 1, &auth_len,
-                     TRUE, hash)) {
-    SILC_LOG_ERROR(("Could not compute signature"));
-    silc_buffer_clear(sign);
-    silc_buffer_free(sign);
-    silc_free(pk);
+    e->encoded(NULL, e->context);
+    silc_sfree(stack, pk);
+    silc_sfree(stack, e);
+    silc_stack_free(stack);
     return NULL;
   }
 
-  /* Encode the SILC_MESSAGE_FLAG_SIGNED Payload */
+  /* Compute signature */
+  op = silc_pkcs_sign(private_key, sign->data, silc_buffer_len(sign),
+                     TRUE, hash, silc_message_signed_payload_encode_cb, e);
 
-  buffer = silc_buffer_alloc_size(4 + pk_len + 2 + auth_len);
-  if (!buffer) {
-    silc_buffer_clear(sign);
-    silc_buffer_free(sign);
-    memset(auth_data, 0, sizeof(auth_data));
-    silc_free(pk);
-    return NULL;
-  }
-
-  silc_buffer_format(buffer,
-                    SILC_STR_UI_SHORT(pk_len),
-                    SILC_STR_UI_SHORT(pk_type),
-                    SILC_STR_END);
-
-  if (pk_len && pk) {
-    silc_buffer_pull(buffer, 4);
-    silc_buffer_format(buffer,
-                      SILC_STR_UI_XNSTRING(pk, pk_len),
-                      SILC_STR_END);
-    silc_buffer_push(buffer, 4);
-  }
-
-  silc_buffer_pull(buffer, 4 + pk_len);
-  silc_buffer_format(buffer,
-                    SILC_STR_UI_SHORT(auth_len),
-                    SILC_STR_UI_XNSTRING(auth_data, auth_len),
-                    SILC_STR_END);
-  silc_buffer_push(buffer, 4 + pk_len);
-
-  SILC_LOG_HEXDUMP(("sig payload"), buffer->data, silc_buffer_len(buffer));
-
-  memset(auth_data, 0, sizeof(auth_data));
-  silc_buffer_clear(sign);
-  silc_buffer_free(sign);
-  silc_free(pk);
-
-  return buffer;
+  return op;
 }
 
-
 /***************************** Payload parsing ******************************/
 
 /* Decrypts the Message Payload. The `data' is the actual Message Payload. */
@@ -300,19 +379,8 @@ SilcBool silc_message_payload_decrypt(unsigned char *data,
     silc_hmac_update(hmac, receiver_id, receiver_id_len);
     silc_hmac_final(hmac, mac, &mac_len);
     if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
-#if 0
       SILC_LOG_DEBUG(("Message MAC does not match"));
       return FALSE;
-#else
-      /* Check for old style message MAC.  Remove this check at some point. */
-      silc_hmac_init(hmac);
-      silc_hmac_update(hmac, data, data_len - mac_len);
-      silc_hmac_final(hmac, mac, &mac_len);
-      if (silc_unlikely(memcmp(data + (data_len - mac_len), mac, mac_len))) {
-       SILC_LOG_DEBUG(("Message MAC does not match"));
-#endif
-       return FALSE;
-      }
     }
     SILC_LOG_DEBUG(("MAC is Ok"));
   }
@@ -477,16 +545,13 @@ SilcBool silc_message_payload_encrypt(unsigned char *data,
                                      SilcCipher cipher,
                                      SilcHmac hmac)
 {
-#if 0
   unsigned char sid[32], rid[32];
   SilcUInt32 sid_len = 0, rid_len = 0;
-#endif /* 0 */
 
   /* Encrypt payload of the packet */
   if (silc_unlikely(!silc_cipher_encrypt(cipher, data, data, data_len, iv)))
     return FALSE;
 
-#if 0 /* For now this is disabled.  Enable at 1.1.x or 1.2 at the latest. */
   /* Encode IDs */
   silc_id_id2str(&sender_id->u.client_id, SILC_ID_CLIENT, sid, sizeof(sid),
                 &sid_len);
@@ -496,15 +561,12 @@ SilcBool silc_message_payload_encrypt(unsigned char *data,
   else if (receiver_id->type == SILC_ID_CHANNEL)
     silc_id_id2str(&receiver_id->u.channel_id, SILC_ID_CHANNEL, rid,
                   sizeof(rid), &rid_len);
-#endif /* 0 */
 
   /* Compute the MAC of the encrypted message data */
   silc_hmac_init(hmac);
   silc_hmac_update(hmac, data, true_len);
-#if 0
   silc_hmac_update(hmac, sid, sid_len);
   silc_hmac_update(hmac, rid, rid_len);
-#endif /* 0 */
   silc_hmac_final(hmac, data + true_len, NULL);
 
   return TRUE;
@@ -512,8 +574,7 @@ SilcBool silc_message_payload_encrypt(unsigned char *data,
 
 /* Encrypt message payload */
 
-static int silc_message_payload_encode_encrypt(SilcStack stack,
-                                              SilcBuffer buffer,
+static int silc_message_payload_encode_encrypt(SilcBuffer buffer,
                                               void *value, void *context)
 {
   SilcMessageEncode *e = context;
@@ -529,82 +590,106 @@ static int silc_message_payload_encode_encrypt(SilcStack stack,
   if (silc_unlikely(!silc_message_payload_encrypt(buffer->head,
                                                  e->payload_len,
                                                  silc_buffer_headlen(buffer),
-                                                 e->iv, e->sid, e->rid,
+                                                 e->iv, &e->sid, &e->rid,
                                                  e->cipher, e->hmac)))
     return -1;
 
   return mac_len;
 }
 
-/* Compute message signature */
-
-static int silc_message_payload_encode_sig(SilcStack stack,
-                                          SilcBuffer buffer,
-                                          void *value, void *context)
+/* Finalize message payload encoding */
+
+static void
+silc_message_payload_encode_final(SilcBuffer buffer,
+                                 SilcMessageFlags flags,
+                                 SilcCipher cipher,
+                                 SilcHmac hmac,
+                                 unsigned char *iv,
+                                 SilcUInt32 iv_len,
+                                 SilcUInt32 payload_len,
+                                 SilcID *sender_id,
+                                 SilcID *receiver_id,
+                                 SilcStack stack,
+                                 SilcBuffer signature,
+                                 SilcMessagePayloadEncoded encoded,
+                                 void *context)
 {
-  SilcMessageEncode *e = context;
-  SilcBuffer sig;
-  int len;
-
-  if (!(e->flags & SILC_MESSAGE_FLAG_SIGNED))
-    return 0;
+  SilcMessageEncode e;
 
-  sig = silc_message_signed_payload_encode(buffer->head,
-                                          silc_buffer_headlen(buffer),
-                                          e->public_key, e->private_key,
-                                          e->hash);
-  if (silc_unlikely(!sig))
-    return -1;
+  e.flags = flags;
+  e.cipher = cipher;
+  e.hmac = hmac;
+  e.sid = *sender_id;
+  e.rid = *receiver_id;
+  e.iv = iv;
+  e.payload_len = payload_len;
 
-  len = silc_buffer_format(buffer,
-                          SILC_STR_DATA(silc_buffer_data(sig),
-                                        silc_buffer_len(sig)),
-                          SILC_STR_END);
-  if (silc_unlikely(len < 0)) {
-    silc_buffer_free(sig);
-    return -1;
+  /* Encrypt */
+  if (silc_buffer_format(buffer,
+                        SILC_STR_DATA(silc_buffer_data(signature),
+                                      silc_buffer_len(signature)),
+                        SILC_STR_DATA(iv, iv_len),
+                        SILC_STR_FUNC(silc_message_payload_encode_encrypt,
+                                      NULL, &e),
+                        SILC_STR_END) < 0) {
+    silc_buffer_sfree(stack, buffer);
+    encoded(NULL, context);
+    return;
   }
 
-  silc_buffer_free(sig);
-  return len;
+  /* Deliver message payload */
+  silc_buffer_start(buffer);
+  encoded(buffer, context);
+
+  silc_buffer_sfree(stack, buffer);
+  silc_buffer_sfree(stack, signature);
+  silc_stack_free(stack);
 }
 
 /* Encodes Message Payload into a buffer and returns it. */
 
-SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
-                                      const unsigned char *data,
-                                      SilcUInt32 data_len,
-                                      SilcBool generate_iv,
-                                      SilcBool private_message,
-                                      SilcCipher cipher,
-                                      SilcHmac hmac,
-                                      SilcRng rng,
-                                      SilcPublicKey public_key,
-                                      SilcPrivateKey private_key,
-                                      SilcHash hash,
-                                      SilcID *sender_id,
-                                      SilcID *receiver_id,
-                                      SilcBuffer buffer)
+SilcAsyncOperation
+silc_message_payload_encode(SilcMessageFlags flags,
+                           const unsigned char *data,
+                           SilcUInt32 data_len,
+                           SilcBool generate_iv,
+                           SilcBool private_message,
+                           SilcCipher cipher,
+                           SilcHmac hmac,
+                           SilcRng rng,
+                           SilcPublicKey public_key,
+                           SilcPrivateKey private_key,
+                           SilcHash hash,
+                           SilcID *sender_id,
+                           SilcID *receiver_id,
+                           SilcStack stack,
+                           SilcMessagePayloadEncoded encoded,
+                           void *context)
 {
   SilcUInt32 pad_len = 0, mac_len = 0, iv_len = 0;
   unsigned char pad[16], iv[SILC_CIPHER_MAX_IV_SIZE];
-  SilcBuffer buf = NULL;
-  SilcMessageEncode e;
+  SilcBuffer buffer;
   int i;
 
   SILC_LOG_DEBUG(("Encoding Message Payload"));
 
-  if (silc_unlikely(!data_len))
+  if (silc_unlikely(!data_len)) {
+    encoded(NULL, context);
     return NULL;
-  if (silc_unlikely(!private_message && (!cipher || !hmac)))
+  }
+  if (silc_unlikely(!private_message && (!cipher || !hmac))) {
+    encoded(NULL, context);
     return NULL;
+  }
 
-  if (!buffer) {
-    buf = buffer = silc_buffer_alloc(0);
-    if (silc_unlikely(!buf))
-      return NULL;
+  stack = silc_stack_alloc(0, stack ? stack : silc_crypto_stack());
+
+  buffer = silc_buffer_salloc(stack, 0);
+  if (silc_unlikely(!buffer)) {
+    encoded(NULL, context);
+    silc_stack_free(stack);
+    return NULL;
   }
-  silc_buffer_reset(buffer);
 
   /* For channel messages IV is always generated */
   if (!private_message && !generate_iv)
@@ -638,35 +723,55 @@ SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
     }
   }
 
-  e.flags = flags;
-  e.public_key = public_key;
-  e.private_key = private_key;
-  e.hash = hash;
-  e.cipher = cipher;
-  e.hmac = hmac;
-  e.sid = sender_id;
-  e.rid = receiver_id;
-  e.iv = iv_len ? iv : NULL;
-  e.payload_len = 6 + data_len + pad_len;
-
   /* Encode the Message Payload */
   if (silc_buffer_format(buffer,
+                        SILC_STR_ADVANCE,
                         SILC_STR_UI_SHORT(flags),
                         SILC_STR_UI_SHORT(data_len),
                         SILC_STR_DATA(data, data_len),
                         SILC_STR_UI_SHORT(pad_len),
                         SILC_STR_DATA(pad, pad_len),
-                        SILC_STR_FUNC(silc_message_payload_encode_sig,
-                                      NULL, &e),
-                        SILC_STR_DATA(iv, iv_len),
-                        SILC_STR_FUNC(silc_message_payload_encode_encrypt,
-                                      NULL, &e),
                         SILC_STR_END) < 0) {
-    silc_buffer_free(buf);
+    silc_buffer_sfree(stack, buffer);
+    encoded(NULL, context);
+    silc_stack_free(stack);
     return NULL;
   }
 
-  return buffer;
+  if (flags & SILC_MESSAGE_FLAG_SIGNED) {
+    SilcMessageEncode *e = silc_scalloc(stack, 1, sizeof(*e));
+    if (!e) {
+      silc_buffer_sfree(stack, buffer);
+      encoded(NULL, context);
+      silc_stack_free(stack);
+      return NULL;
+    }
+
+    e->stack = stack;
+    e->buffer = buffer;
+    e->flags = flags;
+    e->public_key = public_key;
+    e->private_key = private_key;
+    e->hash = hash;
+    e->cipher = cipher;
+    e->hmac = hmac;
+    e->sid = *sender_id;
+    e->rid = *receiver_id;
+    e->iv = iv_len ? iv : NULL;
+    e->iv_len = iv_len;
+    e->payload_len = 6 + data_len + pad_len;
+
+    /* Compute signature */
+    return silc_message_signed_payload_encode(buffer, e);
+  }
+
+  /* Finalize */
+  silc_message_payload_encode_final(buffer, flags, cipher, hmac,
+                                   iv_len ? iv : NULL, iv_len,
+                                   6 + data_len + pad_len,
+                                   sender_id, receiver_id, stack, NULL,
+                                   encoded, context);
+  return NULL;
 }
 
 /* Free's Message Payload */
@@ -711,53 +816,59 @@ unsigned char *silc_message_get_mac(SilcMessagePayload payload)
 
 /* Verify the signature in SILC_MESSAGE_FLAG_SIGNED Payload */
 
-SilcAuthResult silc_message_signed_verify(SilcMessagePayload message,
-                                         SilcPublicKey remote_public_key,
-                                         SilcHash hash)
+SilcAsyncOperation
+silc_message_signed_verify(SilcMessagePayload message,
+                          SilcPublicKey remote_public_key,
+                          SilcHash hash,
+                          SilcAuthResultCb result,
+                          void *context)
 {
-  int ret = SILC_AUTH_FAILED;
+  SilcAsyncOperation op;
   SilcBuffer sign, tmp;
+  SilcStack stack = NULL;
   SilcMessageSignedPayload sig = &message->sig;
 
   if (!(message->flags & SILC_MESSAGE_FLAG_SIGNED) ||
-      !sig->sign_len || !remote_public_key || !hash)
-    return ret;
+      !sig->sign_len || !remote_public_key || !hash) {
+    result(FALSE, context);
+    return NULL;
+  }
+
+  if (silc_crypto_stack())
+    stack = silc_stack_alloc(0, silc_crypto_stack());
 
   /* Generate the signature verification data, the Message Payload */
-  tmp = silc_buffer_alloc_size(6 + message->data_len + message->pad_len);
-  silc_buffer_format(tmp,
-                    SILC_STR_UI_SHORT(message->flags),
-                    SILC_STR_UI_SHORT(message->data_len),
-                    SILC_STR_UI_XNSTRING(message->data, message->data_len),
-                    SILC_STR_UI_SHORT(message->pad_len),
-                    SILC_STR_UI_XNSTRING(message->pad, message->pad_len),
-                    SILC_STR_END);
-  sign = silc_message_signed_encode_data(tmp->data, silc_buffer_len(tmp),
+  tmp = silc_buffer_salloc_size(stack,
+                               6 + message->data_len + message->pad_len);
+  silc_buffer_sformat(stack, tmp,
+                     SILC_STR_UI_SHORT(message->flags),
+                     SILC_STR_UI_SHORT(message->data_len),
+                     SILC_STR_DATA(message->data, message->data_len),
+                     SILC_STR_UI_SHORT(message->pad_len),
+                     SILC_STR_DATA(message->pad, message->pad_len),
+                     SILC_STR_END);
+  sign = silc_message_signed_encode_data(stack, tmp->data, silc_buffer_len(tmp),
                                         sig->pk_data, sig->pk_len,
                                         sig->pk_type);
   silc_buffer_clear(tmp);
-  silc_buffer_free(tmp);
-
-  if (!sign)
-    return ret;
+  silc_buffer_sfree(stack, tmp);
 
-  /* Verify the authentication data */
-  if (!silc_pkcs_verify(remote_public_key, sig->sign_data, sig->sign_len,
-                       silc_buffer_data(sign), silc_buffer_len(sign), hash)) {
-    silc_buffer_clear(sign);
-    silc_buffer_free(sign);
-    SILC_LOG_DEBUG(("Signature verification failed"));
-    return ret;
+  if (!sign) {
+    result(FALSE, context);
+    silc_stack_free(stack);
+    return NULL;
   }
 
-  ret = SILC_AUTH_OK;
+  /* Verify the authentication data */
+  op = silc_pkcs_verify(remote_public_key, sig->sign_data, sig->sign_len,
+                       silc_buffer_data(sign), silc_buffer_len(sign), hash,
+                       result, context);
 
   silc_buffer_clear(sign);
-  silc_buffer_free(sign);
-
-  SILC_LOG_DEBUG(("Signature verification successful"));
+  silc_buffer_sfree(stack, sign);
+  silc_stack_free(stack);
 
-  return ret;
+  return op;
 }
 
 /* Return the public key from the payload */
index 99e9d988d94aedfcffbc6790938e396df602a298..ef6ed3a8af6778147fe470cef49fd99c15c74ce0 100644 (file)
@@ -231,34 +231,54 @@ SilcBool silc_message_payload_encrypt(unsigned char *data,
                                      SilcCipher cipher,
                                      SilcHmac hmac);
 
+/****f* silccore/SilcMessageAPI/SilcMessagePayloadEncoded
+ *
+ * SYNOPSIS
+ *
+ *    typedef void (*SilcMessagePayloadEncoded)(const SilcBuffer message,
+ *                                              void *context);
+ *
+ * DESCRIPTION
+ *
+ *    This callback is given as arugment to silc_message_payload_encode
+ *    and will be called when the message payload has been encoded.  If
+ *    `message' is NULL, encoding failed.
+ *
+ ***/
+typedef void (*SilcMessagePayloadEncoded)(SilcBuffer message,
+                                         void *context);
+
 /****f* silccore/SilcMessageAPI/silc_message_payload_encode
  *
  * SYNOPSIS
  *
- *    SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
- *                                           const unsigned char *data,
- *                                           SilcUInt32 data_len,
- *                                           SilcBool generate_iv,
- *                                           SilcBool private_message,
- *                                           SilcCipher cipher,
- *                                           SilcHmac hmac,
- *                                           SilcRng rng,
- *                                           SilcPublicKey public_key,
- *                                           SilcPrivateKey private_key,
- *                                           SilcHash hash,
- *                                           SilcID *sender_id,
- *                                           SilcID *receiver_id,
- *                                           SilcBuffer buffer);
+ *    SilcAsyncOperation
+ *    silc_message_payload_encode(SilcMessageFlags flags,
+ *                                const unsigned char *data,
+ *                                SilcUInt32 data_len,
+ *                                SilcBool generate_iv,
+ *                                SilcBool private_message,
+ *                                SilcCipher cipher,
+ *                                SilcHmac hmac,
+ *                                SilcRng rng,
+ *                                SilcPublicKey public_key,
+ *                                SilcPrivateKey private_key,
+ *                                SilcHash hash,
+ *                                SilcID *sender_id,
+ *                                SilcID *receiver_id,
+ *                                SilcStack stack,
+ *                                SilcMessagePayloadEncoded encoded,
+ *                                void *context);
  *
  * DESCRIPTION
  *
- *    Encodes a Message Payload into a buffer and returns it.  This is
- *    used to encode channel messages and private messages into a packet.
- *    If `private_message' is FALSE then this encodes channel message, if
- *    it is TRUE this encodes private message.  If `private_message' is
- *    TRUE then `generate_iv' MUST be FALSE if the private message key
- *    `cipher' is not static key (pre-shared key).  If it is static key
- *    then protocol dictates that IV must be present in the Message Payload
+ *    Encodes a Message Payload into a buffer and returns it to the `encoded'
+ *    callback.  This is used to encode channel messages and private messages
+ *    into a packet.  If `private_message' is FALSE then this encodes channel
+ *    message, if it is TRUE this encodes private message.  If
+ *    `private_message' is TRUE then `generate_iv' MUST be FALSE if the private
+ *    message key `cipher' is not static key (pre-shared key).  If it is static
+ *    key then protocol dictates that IV must be present in the Message Payload
  *    and `generate_iv' must be TRUE.  The caller must know whether the key
  *    is static or not for private messages.  If the key was generated with
  *    Key Agreement protocol then `generate_iv' is always FALSE.  For
@@ -281,26 +301,28 @@ SilcBool silc_message_payload_encrypt(unsigned char *data,
  *    The `sender_id' is the ID message sender and `receiver_id' is ID of
  *    message receiver.
  *
- *    If the `buffer' is non-NULL then the payload will be encoded into
- *    that buffer.  The same buffer is returned.  Otherwise new buffer is
- *    allocated and returned.  The `buffer' will be automatically enlarged
- *    if the payload does not fit to it.
+ *    If `stack' is non-NULL the message payload is allocated from stack.
+ *    The memory will be returned back to `stack' after the `encoded' has
+ *    been called.
  *
  ***/
-SilcBuffer silc_message_payload_encode(SilcMessageFlags flags,
-                                      const unsigned char *data,
-                                      SilcUInt32 data_len,
-                                      SilcBool generate_iv,
-                                      SilcBool private_message,
-                                      SilcCipher cipher,
-                                      SilcHmac hmac,
-                                      SilcRng rng,
-                                      SilcPublicKey public_key,
-                                      SilcPrivateKey private_key,
-                                      SilcHash hash,
-                                      SilcID *sender_id,
-                                      SilcID *receiver_id,
-                                      SilcBuffer buffer);
+SilcAsyncOperation
+silc_message_payload_encode(SilcMessageFlags flags,
+                           const unsigned char *data,
+                           SilcUInt32 data_len,
+                           SilcBool generate_iv,
+                           SilcBool private_message,
+                           SilcCipher cipher,
+                           SilcHmac hmac,
+                           SilcRng rng,
+                           SilcPublicKey public_key,
+                           SilcPrivateKey private_key,
+                           SilcHash hash,
+                           SilcID *sender_id,
+                           SilcID *receiver_id,
+                           SilcStack stack,
+                           SilcMessagePayloadEncoded encoded,
+                           void *context);
 
 /****f* silccore/SilcMessageAPI/silc_message_payload_free
  *
@@ -364,22 +386,27 @@ unsigned char *silc_message_get_mac(SilcMessagePayload payload);
  *
  * SYNOPSIS
  *
- *    SilcAuthResult
+ *    SilcAsyncOperation
  *    silc_message_signed_verify(SilcMessagePayload message,
  *                               SilcPublicKey remote_public_key,
- *                               SilcHash hash);
+ *                               SilcHash hash,
+ *                               SilcAuthResultCb result,
+ *                               void *context);
+ *
  *
  * DESCRIPTION
  *
  *    This routine can be used to verify the digital signature from the
  *    message indicated by `message'.  The signature is present only if
- *    the SILC_MESSAGE_FLAG_SIGNED is set in the message flags.  This
- *    returns SILC_AUTH_OK if the signature verification was successful.
+ *    the SILC_MESSAGE_FLAG_SIGNED is set in the message flags.  The
+ *    result of the verification is returned to `result' callback.
  *
  ***/
-SilcAuthResult silc_message_signed_verify(SilcMessagePayload message,
-                                         SilcPublicKey remote_public_key,
-                                         SilcHash hash);
+SilcAsyncOperation silc_message_signed_verify(SilcMessagePayload message,
+                                             SilcPublicKey remote_public_key,
+                                             SilcHash hash,
+                                             SilcAuthResultCb result,
+                                             void *context);
 
 /****f* silccore/SilcMessageAPI/silc_message_signed_get_public_key
  *