Exemple #1
0
int cmd_serval_verify(const char *sas_key,
		   const size_t sas_key_len,
		   const unsigned char *msg,
		   const size_t msg_len,
		   const char *sig,
		   const size_t sig_len) {
  int verdict = 0;
  
  unsigned char bin_sig[SIGNATURE_BYTES];
  unsigned char bin_sas[SAS_SIZE];
  
  CHECK_ERR(sig_len == 2*SIGNATURE_BYTES,"Invalid signature");
  CHECK_ERR(sas_key_len == 2*SAS_SIZE,"Invalid SAS key");
  
  // convert signature from hex to binary
  CHECK_ERR(fromhexstr(bin_sig,sig,SIGNATURE_BYTES) == 0,"Invalid signature");
  CHECK_ERR(fromhexstr(bin_sas,sas_key,SAS_SIZE) == 0,"Invalid SAS key");
  
  DEBUG("Message to verify:\n%s",msg);
  
  unsigned char hash[crypto_hash_sha512_BYTES];
  crypto_hash_sha512(hash,msg,msg_len);
  
  if (crypto_verify_signature(bin_sas, hash, crypto_hash_sha512_BYTES,
    &bin_sig[0], SIGNATURE_BYTES) == 0)
    verdict = 1;  // successfully verified
    
error:
  return verdict;
}
Exemple #2
0
ATF_TC_BODY(isc_aes128, tc) {
	UNUSED(tc);

	aes_testcase_t testcases[] = {
		/* Test 1 (KAT ECBVarTxt128 #3) */
		{
			"00000000000000000000000000000000",
			"F0000000000000000000000000000000",
			"96D9FD5CC4F07441727DF0F33E401A36"
		},
		/* Test 2 (KAT ECBVarTxt128 #123) */
		{
			"00000000000000000000000000000000",
			"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
			"F9B0FDA0C4A898F5B9E6F661C4CE4D07"
		},
		/* Test 3 (KAT ECBVarKey128 #3) */
		{
			"F0000000000000000000000000000000",
			"00000000000000000000000000000000",
			"970014D634E2B7650777E8E84D03CCD8"
		},
		/* Test 4 (KAT ECBVarKey128 #123) */
		{
			"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
			"00000000000000000000000000000000",
			"41C78C135ED9E98C096640647265DA1E"
		},
		/* Test 5 (KAT ECBGFSbox128 #3) */
		{
			"00000000000000000000000000000000",
			"6A118A874519E64E9963798A503F1D35",
			"DC43BE40BE0E53712F7E2BF5CA707209"
		},
		/* Test 6 (KAT ECBKeySbox128 #3) */
		{
			"B6364AC4E1DE1E285EAF144A2415F7A0",
			"00000000000000000000000000000000",
			"5D9B05578FC944B3CF1CCF0E746CD581"
		},
		{ NULL, NULL, NULL }
	};

	aes_testcase_t *testcase = testcases;

	while (testcase->key != NULL) {
		len = fromhexstr(testcase->key, key);
		ATF_CHECK_EQ(len, ISC_AES128_KEYLENGTH);
		len = fromhexstr(testcase->input, plaintext);
		ATF_CHECK_EQ(len, ISC_AES_BLOCK_LENGTH);
		isc_aes128_crypt(key, plaintext, ciphertext);
		ATF_CHECK(tohexstr(ciphertext, str) == ISC_R_SUCCESS);
		ATF_CHECK_STREQ(str, testcase->result);

		testcase++;
	}
}
Exemple #3
0
ATF_TC_BODY(isc_aes192, tc) {
	UNUSED(tc);

	aes_testcase_t testcases[] = {
		/* Test 1 (KAT ECBVarTxt192 #3) */
		{
			"000000000000000000000000000000000000000000000000",
			"F0000000000000000000000000000000",
			"2A560364CE529EFC21788779568D5555"
		},
		/* Test 2 (KAT ECBVarTxt192 #123) */
		{
			"000000000000000000000000000000000000000000000000",
			"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
			"2AABB999F43693175AF65C6C612C46FB"
		},
		/* Test 3 (KAT ECBVarKey192 #3) */
		{
			"F00000000000000000000000000000000000000000000000",
			"00000000000000000000000000000000",
			"180B09F267C45145DB2F826C2582D35C"
		},
		/* Test 4 (KAT ECBVarKey192 #187) */
		{
			"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
			"00000000000000000000000000000000",
			"EACF1E6C4224EFB38900B185AB1DFD42"
		},
		/* Test 5 (KAT ECBGFSbox192 #3) */
		{
			"000000000000000000000000000000000000000000000000",
			"51719783D3185A535BD75ADC65071CE1",
			"4F354592FF7C8847D2D0870CA9481B7C"
		},
		/* Test 6 (KAT ECBKeySbox192 #3) */
		{
			"CD62376D5EBB414917F0C78F05266433DC9192A1EC943300",
			"00000000000000000000000000000000",
			"7F6C25FF41858561BB62F36492E93C29"
		},
		{ NULL, NULL, NULL }
	};

	aes_testcase_t *testcase = testcases;

	while (testcase->key != NULL) {
		len = fromhexstr(testcase->key, key);
		ATF_CHECK_EQ(len, ISC_AES192_KEYLENGTH);
		len = fromhexstr(testcase->input, plaintext);
		ATF_CHECK_EQ(len, ISC_AES_BLOCK_LENGTH);
		isc_aes192_crypt(key, plaintext, ciphertext);
		ATF_CHECK(tohexstr(ciphertext, str) == ISC_R_SUCCESS);
		ATF_CHECK_STREQ(str, testcase->result);

		testcase++;
	}
}
Exemple #4
0
ATF_TC_BODY(isc_aes256, tc) {
	UNUSED(tc);

	aes_testcase_t testcases[] = {
		/* Test 1 (KAT ECBVarTxt256 #3) */
		{
			"00000000000000000000000000000000"
			"00000000000000000000000000000000",
			"F0000000000000000000000000000000",
			"7F2C5ECE07A98D8BEE13C51177395FF7"
		},
		/* Test 2 (KAT ECBVarTxt256 #123) */
		{
			"00000000000000000000000000000000"
			"00000000000000000000000000000000",
			"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
			"7240E524BC51D8C4D440B1BE55D1062C"
		},
		/* Test 3 (KAT ECBVarKey256 #3) */
		{
			"F0000000000000000000000000000000"
			"00000000000000000000000000000000",
			"00000000000000000000000000000000",
			"1C777679D50037C79491A94DA76A9A35"
		},
		/* Test 4 (KAT ECBVarKey256 #251) */
		{
			"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
			"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0",
			"00000000000000000000000000000000",
			"03720371A04962EAEA0A852E69972858"
		},
		/* Test 5 (KAT ECBGFSbox256 #3) */
		{
			"00000000000000000000000000000000"
			"00000000000000000000000000000000",
			"8A560769D605868AD80D819BDBA03771",
			"38F2C7AE10612415D27CA190D27DA8B4"
		},
		/* Test 6 (KAT ECBKeySbox256 #3) */
		{
			"984CA75F4EE8D706F46C2D98C0BF4A45"
			"F5B00D791C2DFEB191B5ED8E420FD627",
			"00000000000000000000000000000000",
			"4307456A9E67813B452E15FA8FFFE398"
		},
		{ NULL, NULL, NULL }
	};

	aes_testcase_t *testcase = testcases;

	while (testcase->key != NULL) {
		len = fromhexstr(testcase->key, key);
		ATF_CHECK_EQ(len, ISC_AES256_KEYLENGTH);
		len = fromhexstr(testcase->input, plaintext);
		ATF_CHECK_EQ(len, ISC_AES_BLOCK_LENGTH);
		isc_aes256_crypt(key, plaintext, ciphertext);
		ATF_CHECK(tohexstr(ciphertext, str) == ISC_R_SUCCESS);
		ATF_CHECK_STREQ(str, testcase->result);

		testcase++;
	}
}
Exemple #5
0
int
serval_crypto_handler(co_obj_t *self, co_obj_t **output, co_obj_t *params)
{
  CLEAR_ERR();
  
  svl_crypto_ctx *ctx = NULL;
  int list_len = co_list_length(params);
  int keypath = 0;
  
  CHECK_ERR(IS_LIST(params) && list_len >= 2, "Invalid params");
  
  if (!strncmp("--keyring=", co_obj_data_ptr(co_list_get_last(params)), 10)) {
    keypath = 1;
    --list_len;
  }
  
  ctx = svl_crypto_ctx_new();
  
  if (co_str_cmp_str(co_list_element(params, 0), "sign") == 0) {
    
    CHECK_ERR(list_len == 2 || list_len == 3, "Invalid arguments");
    
    if (list_len == 3) {
      char *sid_str = _LIST_ELEMENT(params, 1);
      size_t sid_len = co_str_len(co_list_element(params, 1)) - 1;
      CHECK_ERR(sid_len == (2 * SID_SIZE) && str_is_subscriber_id(sid_str) == 1,
		"Invalid SID");
      stowSid(ctx->sid, 0, sid_str);
      ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 2);
      ctx->msg_len = co_str_len(co_list_element(params, 2)) - 1;
      if (keypath) {
	ctx->keyring_path = _LIST_ELEMENT(params, 3) + 10;
	ctx->keyring_len = co_str_len(co_list_element(params, 3)) - 11;
	CHECK_ERR(ctx->keyring_len < PATH_MAX,"Keyring path too long");
      }
    
    } else if (list_len == 2) {
      
      ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 1);
      ctx->msg_len = co_str_len(co_list_element(params, 1)) - 1;
      if (keypath) {
	ctx->keyring_path = _LIST_ELEMENT(params, 2) + 10;
	ctx->keyring_len = co_str_len(co_list_element(params, 2)) - 11;
	CHECK_ERR(ctx->keyring_len < PATH_MAX,"Keyring path too long");
      }

    }
    CHECK_ERR(cmd_serval_sign(ctx), "Failed to create signature");
    
    // convert ctx->signature, ctx->sas_public, and ctx->sid to hex: 
    char sid_str[(2 * SID_SIZE) + 1] = {0};
    strncpy(sid_str, alloca_tohex(ctx->sid, SID_SIZE), 2 * SID_SIZE);
    char sas_str[(2 * crypto_sign_PUBLICKEYBYTES) + 1] = {0};
    strncpy(sas_str, alloca_tohex(ctx->sas_public, crypto_sign_PUBLICKEYBYTES), 2 * crypto_sign_PUBLICKEYBYTES);
    char sig_str[(2 * SIGNATURE_BYTES) + 1] = {0};
    strncpy(sig_str, alloca_tohex(ctx->signature, SIGNATURE_BYTES), 2 * SIGNATURE_BYTES);
    CMD_OUTPUT("SID", co_str8_create(sid_str, (2 * SID_SIZE) + 1, 0));
    CMD_OUTPUT("SAS", co_str8_create(sas_str, (2 * crypto_sign_PUBLICKEYBYTES) + 1, 0));
    CMD_OUTPUT("signature", co_str8_create(sig_str, (2 * SIGNATURE_BYTES) + 1, 0));
    
  } else if (co_str_cmp_str(co_list_element(params, 0), "verify") == 0) {
    
    CHECK_ERR(!keypath, "Keyring option not available for verification");
    CHECK_ERR(list_len == 4, "Invalid arguments");
    // convert SAS and signature from hex to bin
    CHECK_ERR(fromhexstr(ctx->signature, _LIST_ELEMENT(params, 2), SIGNATURE_BYTES) == 0, "Invalid signature");
    CHECK_ERR(fromhexstr(ctx->sas_public, _LIST_ELEMENT(params, 1), crypto_sign_PUBLICKEYBYTES) == 0, "Invalid SAS key");
    ctx->msg = (unsigned char*)_LIST_ELEMENT(params, 3);
    ctx->msg_len = co_str_len(co_list_element(params, 3)) - 1;

    int verdict = cmd_serval_verify(ctx);
    if (verdict == 1) {
      DEBUG("signature verified");
      CMD_OUTPUT("result", co_bool_create(true, 0));  // successfully verified
      CMD_OUTPUT("verified",co_str8_create("true",sizeof("true"),0));
    } else if (verdict == 0) {
      DEBUG("signature NOT verified");
      CMD_OUTPUT("result", co_bool_create(false, 0));
      CMD_OUTPUT("verified",co_str8_create("false",sizeof("false"),0));
    }
    
  }
  
error:
  INS_ERROR();
  if (ctx)
    svl_crypto_ctx_free(ctx);
  return 1;
}
int rhizome_direct_form_received(rhizome_http_request *r)
{
  const char *submitBareFileURI=confValueGet("rhizome.api.addfile.uri", NULL);

  /* Process completed form based on the set of fields seen */
  if (!strcmp(r->path,"/rhizome/import")) {
    switch(r->fields_seen) {
    case RD_MIME_STATE_MANIFESTHEADERS | RD_MIME_STATE_DATAHEADERS: {
	/* Got a bundle to import */
	DEBUGF("Call bundle import for rhizomedata.%d.{data,file}",
	       r->alarm.poll.fd);
	strbuf manifest_path = strbuf_alloca(50);
	strbuf payload_path = strbuf_alloca(50);
	strbuf_sprintf(manifest_path, "rhizomedirect.%d.manifest", r->alarm.poll.fd);
	strbuf_sprintf(payload_path, "rhizomedirect.%d.data", r->alarm.poll.fd);
	int ret = rhizome_bundle_import_files(strbuf_str(manifest_path), strbuf_str(payload_path), 1); // ttl = 1
	
	DEBUGF("Import returned %d",ret);
	
	rhizome_direct_clear_temporary_files(r);
	/* report back to caller.
	  200 = ok, which is probably appropriate for when we already had the bundle.
	  201 = content created, which is probably appropriate for when we successfully
	  import a bundle (or if we already have it).
	  403 = forbidden, which might be appropriate if we refuse to accept it, e.g.,
	  the import fails due to malformed data etc.
	  (should probably also indicate if we have a newer version if possible)
	*/
	switch (ret) {
	case 0:
	  return rhizome_server_simple_http_response(r, 201, "Bundle succesfully imported.");
	case 2:
	  return rhizome_server_simple_http_response(r, 200, "Bundle already imported.");
	}
	return rhizome_server_simple_http_response(r, 500, "Server error: Rhizome import command failed.");
      }
      break;     
    default:
      /* Clean up after ourselves */
      rhizome_direct_clear_temporary_files(r);	     
    }
  } else if (!strcmp(r->path,"/rhizome/enquiry")) {
    int fd=-1;
    char file[1024];
    switch(r->fields_seen) {
    case RD_MIME_STATE_DATAHEADERS:
      /* Read data buffer in, pass to rhizome direct for comparison with local
	 rhizome database, and send back responses. */
      snprintf(file,1024,"rhizomedirect.%d.%s",r->alarm.poll.fd,"data");
      fd=open(file,O_RDONLY);
      if (fd == -1) {
	WHYF_perror("open(%s, O_RDONLY)", alloca_str_toprint(file));
	/* Clean up after ourselves */
	rhizome_direct_clear_temporary_files(r);	     
	return rhizome_server_simple_http_response(r,500,"Couldn't read a file");
      }
      struct stat stat;
      if (fstat(fd, &stat) == -1) {
	WHYF_perror("stat(%d)", fd);
	/* Clean up after ourselves */
	close(fd);
	rhizome_direct_clear_temporary_files(r);	     
	return rhizome_server_simple_http_response(r,500,"Couldn't stat a file");
      }
      unsigned char *addr = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);
      if (addr==MAP_FAILED) {
	WHYF_perror("mmap(NULL, %lld, PROT_READ, MAP_SHARED, %d, 0)", (long long) stat.st_size, fd);
	/* Clean up after ourselves */
	close(fd);
	rhizome_direct_clear_temporary_files(r);	     
	return rhizome_server_simple_http_response(r,500,"Couldn't mmap() a file");
      }
      /* Ask for a fill response.  Regardless of the size of the set of BARs passed
	 to us, we will allow up to 64KB of response. */
      rhizome_direct_bundle_cursor 
	*c=rhizome_direct_get_fill_response(addr,stat.st_size,65536);
      munmap(addr,stat.st_size);
      close(fd);

      if (c)
	{
	  /* TODO: Write out_buffer as the body of the response.
	     We should be able to do this using the async framework fairly easily.
	  */
	  
	  int bytes=c->buffer_offset_bytes+c->buffer_used;
	  r->buffer=malloc(bytes+1024);
	  r->buffer_size=bytes+1024;
	  r->buffer_offset=0;
	  assert(r->buffer);

	  /* Write HTTP response header */
	  struct http_response hr;
	  hr.result_code=200;
	  hr.content_type="binary/octet-stream";
	  hr.content_length=bytes;
	  hr.body=NULL;
	  r->request_type=0;
	  rhizome_server_set_response(r,&hr);
	  assert(r->buffer_offset<1024);

	  /* Now append body and send it back. */
	  bcopy(c->buffer,&r->buffer[r->buffer_length],bytes);
	  r->buffer_length+=bytes;
	  r->buffer_offset=0;

	  /* Clean up cursor after sending response */
	  rhizome_direct_bundle_iterator_free(&c);
	  /* Clean up after ourselves */
	  rhizome_direct_clear_temporary_files(r);	     

	  return 0;
	}
      else
	{
	  return rhizome_server_simple_http_response(r,500,"Could not get response to enquiry");
	}

      /* Clean up after ourselves */
      rhizome_direct_clear_temporary_files(r);	     
      break;
    default:
      /* Clean up after ourselves */
      rhizome_direct_clear_temporary_files(r);	     

      return rhizome_server_simple_http_response(r, 404, "/rhizome/enquiry requires 'data' field");
    }
  }  
  /* Allow servald to be configured to accept files without manifests via HTTP
     from localhost, so that rhizome bundles can be created programatically.
     There are probably still some security loop-holes here, which is part of
     why we leave it disabled by default, but it will be sufficient for testing
     possible uses, including integration with OpenDataKit.
  */
  else if (submitBareFileURI&&(!strcmp(r->path,submitBareFileURI))) {
    if (strcmp(inet_ntoa(r->requestor.sin_addr),
	       confValueGet("rhizome.api.addfile.allowedaddress","127.0.0.1")))
      {	
	DEBUGF("rhizome.api.addfile request received from %s, but is only allowed from %s",
	       inet_ntoa(r->requestor.sin_addr),
	       confValueGet("rhizome.api.addfile.allowedaddress", "127.0.0.1"));

	rhizome_direct_clear_temporary_files(r);	     
	return rhizome_server_simple_http_response(r,404,"Not available from here.");
      }

    switch(r->fields_seen) {
    case RD_MIME_STATE_DATAHEADERS:
      /* We have been given a file without a manifest, we should only
	 accept if it we are configured to do so, and the connection is from
	 localhost.  Otherwise people could cause your servald to create
	 arbitrary bundles, which would be bad.
      */
      /* A bundle to import */
      DEBUGF("Call bundle import sans-manifest for rhizomedata.%d.{data,file}",
	     r->alarm.poll.fd);
      
      char filepath[1024];
      snprintf(filepath,1024,"rhizomedirect.%d.data",r->alarm.poll.fd);

      const char *manifestTemplate
	=confValueGet("rhizome.api.addfile.manifesttemplate", NULL);
      
      if (manifestTemplate&&access(manifestTemplate, R_OK) != 0)
	{
	  rhizome_direct_clear_temporary_files(r);	     
	  return rhizome_server_simple_http_response(r,500,"rhizome.api.addfile.manifesttemplate points to a file I could not read.");
	}

      rhizome_manifest *m = rhizome_new_manifest();
      if (!m)
	{
	  rhizome_server_simple_http_response(r,500,"No free manifest slots. Try again later.");
	  rhizome_direct_clear_temporary_files(r);	     
	  return WHY("Manifest struct could not be allocated -- not added to rhizome");
	}

      if (manifestTemplate)
	if (rhizome_read_manifest_file(m, manifestTemplate, 0) == -1) {
	  rhizome_manifest_free(m);
	  rhizome_direct_clear_temporary_files(r);	     
	  return rhizome_server_simple_http_response(r,500,"rhizome.api.addfile.manifesttemplate can't be read as a manifest.");
	}

      /* Fill in a few missing manifest fields, to make it easier to use when adding new files:
	 - the default service is FILE
	 - use the current time for "date"
	 - if service is file, then use the payload file's basename for "name"
      */
      const char *service = rhizome_manifest_get(m, "service", NULL, 0);
      if (service == NULL) {
	rhizome_manifest_set(m, "service", (service = RHIZOME_SERVICE_FILE));
	if (debug & DEBUG_RHIZOME) DEBUGF("missing 'service', set default service=%s", service);
      } else {
	if (debug & DEBUG_RHIZOME) DEBUGF("manifest contains service=%s", service);
      }
      if (rhizome_manifest_get(m, "date", NULL, 0) == NULL) {
	rhizome_manifest_set_ll(m, "date", (long long) gettime_ms());
	if (debug & DEBUG_RHIZOME) DEBUGF("missing 'date', set default date=%s", rhizome_manifest_get(m, "date", NULL, 0));
      }

      const char *name = rhizome_manifest_get(m, "name", NULL, 0);
      if (name == NULL) {
	name=r->data_file_name;
	rhizome_manifest_set(m, "name", r->data_file_name);
	if (debug & DEBUG_RHIZOME) DEBUGF("missing 'name', set name=\"%s\" from HTTP post field filename specification", name);
      } else {
	if (debug & DEBUG_RHIZOME) DEBUGF("manifest contains name=\"%s\"", name);
      }

      const char *senderhex
	= rhizome_manifest_get(m, "sender", NULL, 0);
      if (!senderhex) senderhex=confValueGet("rhizome.api.addfile.author",NULL);
      unsigned char authorSid[SID_SIZE];
      if (senderhex) fromhexstr(authorSid,senderhex,SID_SIZE);
      const char *bskhex
	=confValueGet("rhizome.api.addfile.bundlesecretkey", NULL);   

      /* Bind an ID to the manifest, and also bind the file.  Then finalise the 
	 manifest. But if the manifest already contains an ID, don't override it. */
      if (rhizome_manifest_get(m, "id", NULL, 0) == NULL) {
	if (rhizome_manifest_bind_id(m, senderhex ? authorSid : NULL)) {
	  rhizome_manifest_free(m);
	  m = NULL;
	  rhizome_direct_clear_temporary_files(r);
	  return rhizome_server_simple_http_response(r,500,"Could not bind manifest to an ID");
	}	
      } else if (bskhex) {
	/* Allow user to specify a bundle secret key so that the same bundle can
	   be updated, rather than creating a new bundle each time. */
	unsigned char bsk[RHIZOME_BUNDLE_KEY_BYTES];
	fromhexstr(bsk,bskhex,RHIZOME_BUNDLE_KEY_BYTES);
	memcpy(m->cryptoSignSecret, bsk, RHIZOME_BUNDLE_KEY_BYTES);
	if (rhizome_verify_bundle_privatekey(m) == -1) {
	  rhizome_manifest_free(m);
	  m = NULL;
	  rhizome_direct_clear_temporary_files(r);
	  return rhizome_server_simple_http_response(r,500,"rhizome.api.addfile.bundlesecretkey did not verify.  Using the right key for the right bundle?");
	}
      } else {
	/* Bundle ID specified, but without a BSK or sender SID specified.
	   Therefore we cannot work out the bundle key, and cannot update the
	   bundle. */
	rhizome_manifest_free(m);
	m = NULL;
	rhizome_direct_clear_temporary_files(r);
	return rhizome_server_simple_http_response(r,500,"rhizome.api.addfile.bundlesecretkey not set, and manifest template contains no sender, but template contains a hard-wired bundle ID.  You must specify at least one, or not supply id= in the manifest template.");
	
      }
      
      int encryptP = 0; // TODO Determine here whether payload is to be encrypted.
      if (rhizome_manifest_bind_file(m, filepath, encryptP)) {
	rhizome_manifest_free(m);
	rhizome_direct_clear_temporary_files(r);
	return rhizome_server_simple_http_response(r,500,"Could not bind manifest to file");
      }      
      if (rhizome_manifest_finalise(m)) {
	rhizome_manifest_free(m);
	rhizome_direct_clear_temporary_files(r);
	return rhizome_server_simple_http_response(r,500,
						   "Could not finalise manifest");
      }
      if (rhizome_add_manifest(m,255 /* TTL */)) {
	rhizome_manifest_free(m);
	rhizome_direct_clear_temporary_files(r);
	return rhizome_server_simple_http_response(r,500,
						   "Add manifest operation failed");
      }
            
      DEBUGF("Import sans-manifest appeared to succeed");
      
      /* Respond with the manifest that was added. */
      rhizome_server_simple_http_response(r, 200, (char *)m->manifestdata);

      /* clean up after ourselves */
      rhizome_manifest_free(m);
      rhizome_direct_clear_temporary_files(r);

      return 0;
      break;
    default:
      /* Clean up after ourselves */
      rhizome_direct_clear_temporary_files(r);	     
      
      return rhizome_server_simple_http_response(r, 400, "Rhizome create bundle from file API requires 'data' field");     
    }
  }  

  /* Clean up after ourselves */
  rhizome_direct_clear_temporary_files(r);	     
  /* Report error */
  return rhizome_server_simple_http_response(r, 500, "Something went wrong.  Probably a missing data or manifest part, or invalid combination of URI and data/manifest provision.");

}